Name | imessage-conversation-analyzer JSON |
Version |
2.6.0
JSON |
| download |
home_page | None |
Summary | Analyzes the entire history of a macOS Messages conversation |
upload_time | 2025-02-02 00:34:35 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.9 |
license | The MIT License (MIT)
Copyright (c) 2020-2025 Caleb Evans
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 |
apple
imessage
macos
conversation
chat
analysis
pandas
|
VCS |
 |
bugtrack_url |
|
requirements |
black
build
click
coverage
et_xmlfile
flake8
flake8-black
flake8-isort
freezegun
isort
mccabe
mypy
mypy-extensions
nose2
numpy
openpyxl
packaging
pandas
pathspec
phonenumbers
platformdirs
pyarrow
pycodestyle
pyflakes
pyproject_hooks
python-dateutil
pytypedstream
pytz
setuptools
six
tabulate
typing_extensions
tzdata
tzlocal
wheel
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# iMessage Conversation Analyzer
*Copyright 2020-2025 Caleb Evans*
*Released under the MIT license*
[](https://github.com/caleb531/imessage-conversation-analyzer/actions/workflows/tests.yml)
[](https://coveralls.io/r/caleb531/imessage-conversation-analyzer?branch=main)
iMessage Conversation Analyzer (ICA) is a fully-typed Python library that will
read the contents of an iMessage conversation via the Messages app's database on
macOS. You can then gather various metrics of interest on the messages. The library also includes a CLI utility for easy use.
Much of this program was inspired by and built using findings from [this blog post by Yorgos Askalidis][blog-post].
[blog-post]: https://towardsdatascience.com/heres-how-you-can-access-your-entire-imessage-history-on-your-mac-f8878276c6e9
### Caveats
- Group chats (three or more people) are not supported at this time
- This program only runs on macOS
## Installation
Open a Terminal and run the following:
```sh
pip3 install imessage-conversation-analyzer
```
## Usage
The package includes both a Command Line API for simplicity/convenience, as well
as a Python API for developers who want maximum flexibility.
### Command Line API
To use ICA from the command line, run the `ica` command from the Terminal. The
minimum required arguments are:
1. A path to an analyzer file to run, or the name of a built-in analyzer
2. The first and last name of the contact, via the `-c`/`--contact` flag
1. If the contact has no last name on record, you can just pass the first
name
#### Example
```sh
ica message_totals -c 'Jane Fernbrook'
```
The following outputs a table like:
```
Metric Total
Messages 14535
Messages From Me 7289
Messages From Them 7246
Reactions 5050
Reactions From Me 3901
Reactions From Them 1149
Days Messaged 115
Days Missed 0
Days With No Reply 0
```
#### Built-in analyzers
ICA includes several built-in analyzers out of the box:
1. `message_totals`: a summary of message and reaction counts, by person and in
total, as well as other insightful metrics
2. `attachment_totals`: lists count data by attachment type, including
number of Spotify links shared, YouTube videos, Apple Music, etc.
3. `most_frequent_emojis`: count data for the top 10 most frequently used emojis
across the entire conversation
4. `totals_by_day`: a comprehensive breakdown of message totals for every day
you and the other person have been messaging in the conversation
5. `transcript`: a full, unedited transcript of every message, including
reactions, between you and the other person (attachment files not included)
6. `count_phrases`: count the number of case-insensitive occurrences of any
arbitrary strings across all messages in a conversation (excluding reactions)
#### Filtering
There are several built-in flags you can use to filter messages and attachments.
- `--from-date`: A start date to filter messages by (inclusive); the format must
be ISO 8601-compliant, e.g. YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS
- `--to-date`: An end date to filter messages by (exclusive); the format must be
ISO 8601-compliant, e.g. YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS
- `--from-person`: A reference to the person by whom to filter messages;
accepted values can be `me`, `them`, or `both` (the default)
```sh
ica message_totals -c 'Jane Fernbrook' --from-date 2024-12-01 --to-date 2025-01-01 --from-person them
```
#### Other formats
You can optionally pass the `-f`/`--format` flag to output to a specific format
like CSV (supported formats include `csv`, `excel`/`xlsx`, and `markdown`/`md`).
```sh
ica message_totals -c 'Jane Fernbrook' -f csv
```
```sh
ica ./my_custom_analyzer.py -c 'Jane Fernbrook' -f csv
```
#### Writing to a file
Finally, there is an optional `-o`/`--output` flag if you want to output to a
specified file. ICA will do its best to infer the format from the file
extension, although you could also pass `--format` if you have special filename
requirements.
```sh
ica transcript -c 'Thomas Riverstone' -o ./my_transcript.xlsx
```
### Python API
The Python API is much more powerful, allowing you to integrate ICA into any
type of Python project that can run on macOS. All of the built-in analyzers
(under the `ica/analyzers` directory) actually use this API.
Here's a complete example that shows how to retrieve the transcript of an entire
iMessage conversation with one other person.
```python
# get_my_transcript.py
import pandas as pd
import ica
# Export a transcript of the entire conversation
def main() -> None:
# Allow your program to accept all the same CLI arguments as the `ica`
# command; you can skip calling this if have other means of specifying the
# contact name and output format; you can also add your own arguments this
# way (see the count_phrases analyzer for an example of this)
cli_args = ica.get_cli_parser().parse_args()
# Retrieve the dataframes corresponding to the processed contents of the
# database; dataframes include `messages` and `attachments`
dfs = ica.get_dataframes(
contact_name=cli_args.contact_name,
timezone=cli_args.timezone,
from_date=cli_args.from_date,
to_date=cli_args.to_date,
from_person=cli_args.from_person,
)
# Send the results to stdout (or to file) in the given format
ica.output_results(
pd.DataFrame(
{
"timestamp": dfs.messages["datetime"],
"is_from_me": dfs.messages["is_from_me"],
"is_reaction": dfs.messages["is_reaction"],
# U+FFFC is the object replacement character, which appears as
# the textual message for every attachment
"message": dfs.messages["text"].replace(
r"\ufffc", "(attachment)", regex=True
),
}
),
# The default format (None) corresponds to the pandas default dataframe
# table format
format=cli_args.format,
# When output is None (the default), ICA will print to stdout
output=cli_args.output,
)
if __name__ == "__main__":
main()
```
You can run the above program using the `ica` command, or execute it directly
like any other Python program.
```sh
ica ./get_my_transcript.py -c 'Thomas Riverstone'
```
```sh
python ./get_my_transcript.py -c 'Thomas Riverstone'
```
```sh
python -m get_my_transcript -c 'Thomas Riverstone'
```
You're not limited to writing a command line program, though! The
`ica.get_dataframes()` function is the only function you will need in any
analyzer program. But beyond that, feel free to import other modules, send your
results to other processes, or whatever you need to do!
You can also import any built-in analyzer (for your own post-processing) via the
`ica.analyzers` namespace.
```py
import ica.analyzers.message_totals as message_totals
```
### Errors and exceptions
- `BaseAnalyzerException`: the base exception class for all library-related
errors and exceptions
- `ContactNotFoundError`: raised if the specified contact was not found
- `ConversationNotFoundError`: raised if the specified conversation was not
found
- `FormatNotSupportedError`: raised if the specified format is not supported by
the library
#### Using a specific timezone
By default, all dates and times are in the local timezone of the system on which
ICA is run. If you'd like to change this, you can pass the `--timezone` / `-t`
option to the CLI with an IANA timezone name.
```sh
ica totals_by_day -c 'Daniel Brightingale' -t UTC
```
```sh
ica totals_by_day -c 'Daniel Brightingale' -t America/New_York
```
The equivalent option for the Python API is the `timezone` parameter to
`ica.get_dataframes`:
```python
dfs = ica.get_dataframes(contact_name=my_contact_name, timezone='UTC')
```
## Developer Setup
The following instructions are written for developers who want to run the
package locally, or write their own analyzers.
### 1. Set up virtualenv
```sh
pip3 install virtualenv
```
```sh
virtualenv --python=python3 .virtualenv
source .virtualenv/bin/activate
```
### 2. Install project depdendencies
```sh
pip install -r requirements.txt
```
Raw data
{
"_id": null,
"home_page": null,
"name": "imessage-conversation-analyzer",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": "Caleb Evans <caleb@calebevans.me>",
"keywords": "apple, imessage, macos, conversation, chat, analysis, pandas",
"author": null,
"author_email": "Caleb Evans <caleb@calebevans.me>",
"download_url": "https://files.pythonhosted.org/packages/1e/d4/8e773f12e775dfc347e40cfdcb24aed30d02c134a931e48c2000c79ef3d7/imessage_conversation_analyzer-2.6.0.tar.gz",
"platform": null,
"description": "# iMessage Conversation Analyzer\n\n*Copyright 2020-2025 Caleb Evans* \n*Released under the MIT license*\n\n[](https://github.com/caleb531/imessage-conversation-analyzer/actions/workflows/tests.yml)\n[](https://coveralls.io/r/caleb531/imessage-conversation-analyzer?branch=main)\n\niMessage Conversation Analyzer (ICA) is a fully-typed Python library that will\nread the contents of an iMessage conversation via the Messages app's database on\nmacOS. You can then gather various metrics of interest on the messages. The library also includes a CLI utility for easy use.\n\nMuch of this program was inspired by and built using findings from [this blog post by Yorgos Askalidis][blog-post].\n\n[blog-post]: https://towardsdatascience.com/heres-how-you-can-access-your-entire-imessage-history-on-your-mac-f8878276c6e9\n\n### Caveats\n\n- Group chats (three or more people) are not supported at this time\n- This program only runs on macOS\n\n## Installation\n\nOpen a Terminal and run the following:\n\n```sh\npip3 install imessage-conversation-analyzer\n```\n\n## Usage\n\nThe package includes both a Command Line API for simplicity/convenience, as well\nas a Python API for developers who want maximum flexibility.\n\n### Command Line API\n\nTo use ICA from the command line, run the `ica` command from the Terminal. The\nminimum required arguments are:\n\n1. A path to an analyzer file to run, or the name of a built-in analyzer\n2. The first and last name of the contact, via the `-c`/`--contact` flag\n 1. If the contact has no last name on record, you can just pass the first\n name\n\n#### Example\n\n```sh\nica message_totals -c 'Jane Fernbrook'\n```\n\nThe following outputs a table like:\n\n```\nMetric Total\nMessages 14535\nMessages From Me 7289\nMessages From Them 7246\nReactions 5050\nReactions From Me 3901\nReactions From Them 1149\nDays Messaged 115\nDays Missed 0\nDays With No Reply 0\n```\n\n#### Built-in analyzers\n\nICA includes several built-in analyzers out of the box:\n\n1. `message_totals`: a summary of message and reaction counts, by person and in\n total, as well as other insightful metrics\n2. `attachment_totals`: lists count data by attachment type, including\n number of Spotify links shared, YouTube videos, Apple Music, etc.\n3. `most_frequent_emojis`: count data for the top 10 most frequently used emojis\n across the entire conversation\n4. `totals_by_day`: a comprehensive breakdown of message totals for every day\n you and the other person have been messaging in the conversation\n5. `transcript`: a full, unedited transcript of every message, including\n reactions, between you and the other person (attachment files not included)\n6. `count_phrases`: count the number of case-insensitive occurrences of any\n arbitrary strings across all messages in a conversation (excluding reactions)\n\n#### Filtering\n\nThere are several built-in flags you can use to filter messages and attachments.\n\n- `--from-date`: A start date to filter messages by (inclusive); the format must\n be ISO 8601-compliant, e.g. YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS\n- `--to-date`: An end date to filter messages by (exclusive); the format must be\n ISO 8601-compliant, e.g. YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS\n- `--from-person`: A reference to the person by whom to filter messages;\n accepted values can be `me`, `them`, or `both` (the default)\n\n\n```sh\nica message_totals -c 'Jane Fernbrook' --from-date 2024-12-01 --to-date 2025-01-01 --from-person them\n```\n\n#### Other formats\n\nYou can optionally pass the `-f`/`--format` flag to output to a specific format\nlike CSV (supported formats include `csv`, `excel`/`xlsx`, and `markdown`/`md`).\n\n```sh\nica message_totals -c 'Jane Fernbrook' -f csv\n```\n\n```sh\nica ./my_custom_analyzer.py -c 'Jane Fernbrook' -f csv\n```\n\n#### Writing to a file\n\nFinally, there is an optional `-o`/`--output` flag if you want to output to a\nspecified file. ICA will do its best to infer the format from the file\nextension, although you could also pass `--format` if you have special filename\nrequirements.\n\n```sh\nica transcript -c 'Thomas Riverstone' -o ./my_transcript.xlsx\n```\n\n### Python API\n\nThe Python API is much more powerful, allowing you to integrate ICA into any\ntype of Python project that can run on macOS. All of the built-in analyzers\n(under the `ica/analyzers` directory) actually use this API.\n\nHere's a complete example that shows how to retrieve the transcript of an entire\niMessage conversation with one other person.\n\n```python\n# get_my_transcript.py\n\nimport pandas as pd\n\nimport ica\n\n\n# Export a transcript of the entire conversation\ndef main() -> None:\n # Allow your program to accept all the same CLI arguments as the `ica`\n # command; you can skip calling this if have other means of specifying the\n # contact name and output format; you can also add your own arguments this\n # way (see the count_phrases analyzer for an example of this)\n cli_args = ica.get_cli_parser().parse_args()\n # Retrieve the dataframes corresponding to the processed contents of the\n # database; dataframes include `messages` and `attachments`\n dfs = ica.get_dataframes(\n contact_name=cli_args.contact_name,\n timezone=cli_args.timezone,\n from_date=cli_args.from_date,\n to_date=cli_args.to_date,\n from_person=cli_args.from_person,\n )\n # Send the results to stdout (or to file) in the given format\n ica.output_results(\n pd.DataFrame(\n {\n \"timestamp\": dfs.messages[\"datetime\"],\n \"is_from_me\": dfs.messages[\"is_from_me\"],\n \"is_reaction\": dfs.messages[\"is_reaction\"],\n # U+FFFC is the object replacement character, which appears as\n # the textual message for every attachment\n \"message\": dfs.messages[\"text\"].replace(\n r\"\\ufffc\", \"(attachment)\", regex=True\n ),\n }\n ),\n # The default format (None) corresponds to the pandas default dataframe\n # table format\n format=cli_args.format,\n # When output is None (the default), ICA will print to stdout\n output=cli_args.output,\n )\n\n\nif __name__ == \"__main__\":\n main()\n```\n\nYou can run the above program using the `ica` command, or execute it directly\nlike any other Python program.\n\n```sh\nica ./get_my_transcript.py -c 'Thomas Riverstone'\n```\n\n```sh\npython ./get_my_transcript.py -c 'Thomas Riverstone'\n```\n\n```sh\npython -m get_my_transcript -c 'Thomas Riverstone'\n```\n\nYou're not limited to writing a command line program, though! The\n`ica.get_dataframes()` function is the only function you will need in any\nanalyzer program. But beyond that, feel free to import other modules, send your\nresults to other processes, or whatever you need to do!\n\nYou can also import any built-in analyzer (for your own post-processing) via the\n`ica.analyzers` namespace.\n\n```py\nimport ica.analyzers.message_totals as message_totals\n```\n\n### Errors and exceptions\n\n- `BaseAnalyzerException`: the base exception class for all library-related\n errors and exceptions\n- `ContactNotFoundError`: raised if the specified contact was not found\n- `ConversationNotFoundError`: raised if the specified conversation was not\n found\n- `FormatNotSupportedError`: raised if the specified format is not supported by\n the library\n\n#### Using a specific timezone\n\nBy default, all dates and times are in the local timezone of the system on which\nICA is run. If you'd like to change this, you can pass the `--timezone` / `-t`\noption to the CLI with an IANA timezone name.\n\n```sh\nica totals_by_day -c 'Daniel Brightingale' -t UTC\n```\n\n```sh\nica totals_by_day -c 'Daniel Brightingale' -t America/New_York\n```\n\nThe equivalent option for the Python API is the `timezone` parameter to\n`ica.get_dataframes`:\n\n```python\ndfs = ica.get_dataframes(contact_name=my_contact_name, timezone='UTC')\n```\n\n## Developer Setup\n\nThe following instructions are written for developers who want to run the\npackage locally, or write their own analyzers.\n\n### 1. Set up virtualenv\n\n```sh\npip3 install virtualenv\n```\n\n```sh\nvirtualenv --python=python3 .virtualenv\nsource .virtualenv/bin/activate\n```\n\n### 2. Install project depdendencies\n\n```sh\npip install -r requirements.txt\n```\n",
"bugtrack_url": null,
"license": "The MIT License (MIT)\n \n Copyright (c) 2020-2025 Caleb Evans\n \n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n \n The above copyright notice and this permission notice shall be included in\n all copies or substantial portions of the Software.\n \n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n THE SOFTWARE.\n ",
"summary": "Analyzes the entire history of a macOS Messages conversation",
"version": "2.6.0",
"project_urls": {
"changelog": "https://github.com/caleb531/imessage-conversation-analyzer/releases",
"documentation": "https://github.com/caleb531/imessage-conversation-analyzer#readme",
"homepage": "https://github.com/caleb531/imessage-conversation-analyzer",
"repository": "https://github.com/caleb531/imessage-conversation-analyzer"
},
"split_keywords": [
"apple",
" imessage",
" macos",
" conversation",
" chat",
" analysis",
" pandas"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "8f136f03bf20467ec56601bda812426dbbc663c64996c8a5db41e4e9b5cdc4aa",
"md5": "542b45955b9c23d7ca355f2ef93308a6",
"sha256": "9fd673913ac7284a1133ddaa067e2a651707a51d1f8e97dfd1a2f3cb47207581"
},
"downloads": -1,
"filename": "imessage_conversation_analyzer-2.6.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "542b45955b9c23d7ca355f2ef93308a6",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 28285,
"upload_time": "2025-02-02T00:34:32",
"upload_time_iso_8601": "2025-02-02T00:34:32.391552Z",
"url": "https://files.pythonhosted.org/packages/8f/13/6f03bf20467ec56601bda812426dbbc663c64996c8a5db41e4e9b5cdc4aa/imessage_conversation_analyzer-2.6.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "1ed48e773f12e775dfc347e40cfdcb24aed30d02c134a931e48c2000c79ef3d7",
"md5": "3a4c7a7807b0f0429de4657ce8c50a44",
"sha256": "c886656e1429f05ce9f71eb403f83b9a3ba63e4b5bb388f7d9d8de37eb93b297"
},
"downloads": -1,
"filename": "imessage_conversation_analyzer-2.6.0.tar.gz",
"has_sig": false,
"md5_digest": "3a4c7a7807b0f0429de4657ce8c50a44",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 33559,
"upload_time": "2025-02-02T00:34:35",
"upload_time_iso_8601": "2025-02-02T00:34:35.551251Z",
"url": "https://files.pythonhosted.org/packages/1e/d4/8e773f12e775dfc347e40cfdcb24aed30d02c134a931e48c2000c79ef3d7/imessage_conversation_analyzer-2.6.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-02-02 00:34:35",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "caleb531",
"github_project": "imessage-conversation-analyzer",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [
{
"name": "black",
"specs": [
[
"==",
"24.10.0"
]
]
},
{
"name": "build",
"specs": [
[
"==",
"1.2.2.post1"
]
]
},
{
"name": "click",
"specs": [
[
"==",
"8.1.8"
]
]
},
{
"name": "coverage",
"specs": [
[
"==",
"7.6.10"
]
]
},
{
"name": "et_xmlfile",
"specs": [
[
"==",
"2.0.0"
]
]
},
{
"name": "flake8",
"specs": [
[
"==",
"7.1.1"
]
]
},
{
"name": "flake8-black",
"specs": [
[
"==",
"0.3.6"
]
]
},
{
"name": "flake8-isort",
"specs": [
[
"==",
"6.1.1"
]
]
},
{
"name": "freezegun",
"specs": [
[
"==",
"1.5.1"
]
]
},
{
"name": "isort",
"specs": [
[
"==",
"5.13.2"
]
]
},
{
"name": "mccabe",
"specs": [
[
"==",
"0.7.0"
]
]
},
{
"name": "mypy",
"specs": [
[
"==",
"1.14.1"
]
]
},
{
"name": "mypy-extensions",
"specs": [
[
"==",
"1.0.0"
]
]
},
{
"name": "nose2",
"specs": [
[
"==",
"0.15.1"
]
]
},
{
"name": "numpy",
"specs": [
[
"==",
"1.26.4"
]
]
},
{
"name": "openpyxl",
"specs": [
[
"==",
"3.1.5"
]
]
},
{
"name": "packaging",
"specs": [
[
"==",
"24.2"
]
]
},
{
"name": "pandas",
"specs": [
[
"==",
"2.2.3"
]
]
},
{
"name": "pathspec",
"specs": [
[
"==",
"0.12.1"
]
]
},
{
"name": "phonenumbers",
"specs": [
[
"==",
"8.13.52"
]
]
},
{
"name": "platformdirs",
"specs": [
[
"==",
"4.3.6"
]
]
},
{
"name": "pyarrow",
"specs": [
[
"==",
"18.1.0"
]
]
},
{
"name": "pycodestyle",
"specs": [
[
"==",
"2.12.1"
]
]
},
{
"name": "pyflakes",
"specs": [
[
"==",
"3.2.0"
]
]
},
{
"name": "pyproject_hooks",
"specs": [
[
"==",
"1.2.0"
]
]
},
{
"name": "python-dateutil",
"specs": [
[
"==",
"2.9.0.post0"
]
]
},
{
"name": "pytypedstream",
"specs": [
[
"==",
"0.1.0"
]
]
},
{
"name": "pytz",
"specs": [
[
"==",
"2024.2"
]
]
},
{
"name": "setuptools",
"specs": [
[
"==",
"75.6.0"
]
]
},
{
"name": "six",
"specs": [
[
"==",
"1.17.0"
]
]
},
{
"name": "tabulate",
"specs": [
[
"==",
"0.9.0"
]
]
},
{
"name": "typing_extensions",
"specs": [
[
"==",
"4.12.2"
]
]
},
{
"name": "tzdata",
"specs": [
[
"==",
"2024.2"
]
]
},
{
"name": "tzlocal",
"specs": [
[
"==",
"5.2"
]
]
},
{
"name": "wheel",
"specs": [
[
"==",
"0.45.1"
]
]
}
],
"lcname": "imessage-conversation-analyzer"
}