diff --git a/surfsense_backend/tests/unit/scrapers/reddit/fixtures/sample_post.json b/surfsense_backend/tests/unit/scrapers/reddit/fixtures/sample_post.json new file mode 100644 index 000000000..d2627e6e9 --- /dev/null +++ b/surfsense_backend/tests/unit/scrapers/reddit/fixtures/sample_post.json @@ -0,0 +1 @@ +[{"kind": "Listing", "data": {"after": null, "dist": 1, "modhash": "", "geo_filter": "", "children": [{"kind": "t3", "data": {"approved_at_utc": null, "subreddit": "Python", "selftext": "Post all of your code/projects/showcases/AI slop here. \n\nRecycles once a month.", "user_reports": [], "saved": false, "mod_reason_title": null, "gilded": 0, "clicked": false, "title": "Showcase Thread", "link_flair_richtext": [{"e": "text", "t": "Showcase"}], "subreddit_name_prefixed": "r/Python", "hidden": false, "pwls": 6, "link_flair_css_class": "showcase", "downs": 0, "thumbnail_height": null, "top_awarded_type": null, "hide_score": false, "name": "t3_1tws1w7", "quarantine": false, "link_flair_text_color": "light", "upvote_ratio": 0.87, "author_flair_background_color": null, "subreddit_type": "public", "ups": 27, "total_awards_received": 0, "media_embed": {}, "thumbnail_width": null, "author_flair_template_id": null, "is_original_content": false, "author_fullname": "t2_6l4z3", "secure_media": null, "is_reddit_media_domain": false, "is_meta": false, "category": null, "secure_media_embed": {}, "link_flair_text": "Showcase", "can_mod_post": false, "score": 27, "approved_by": null, "is_created_from_ads_ui": false, "author_premium": true, "thumbnail": "self", "edited": false, "author_flair_css_class": null, "author_flair_richtext": [], "gildings": {}, "content_categories": null, "is_self": true, "mod_note": null, "created": 1780589106.0, "link_flair_type": "richtext", "wls": 6, "removed_by_category": null, "banned_by": null, "author_flair_type": "text", "domain": "self.Python", "allow_live_comments": false, "selftext_html": "

Post all of your code/projects/showcases/AI slop here.

\n\n

Recycles once a month.

\n
", "likes": null, "suggested_sort": null, "banned_at_utc": null, "view_count": null, "archived": false, "no_follow": false, "is_crosspostable": false, "pinned": false, "over_18": false, "all_awardings": [], "awarders": [], "media_only": false, "link_flair_template_id": "f35fb004-c1ff-11ee-8305-565bc5d0cc73", "can_gild": false, "spoiler": false, "locked": false, "author_flair_text": null, "treatment_tags": [], "visited": false, "removed_by": null, "num_reports": null, "distinguished": null, "subreddit_id": "t5_2qh0y", "author_is_blocked": false, "mod_reason_by": null, "removal_reason": null, "link_flair_background_color": "#ff66ac", "id": "1tws1w7", "is_robot_indexable": true, "num_duplicates": 0, "report_reasons": null, "author": "AutoModerator", "discussion_type": null, "num_comments": 207, "send_replies": true, "media": null, "contest_mode": false, "author_patreon_flair": false, "author_flair_text_color": null, "permalink": "/r/Python/comments/1tws1w7/showcase_thread/", "stickied": true, "url": "https://www.reddit.com/r/Python/comments/1tws1w7/showcase_thread/", "subreddit_subscribers": 1493425, "created_utc": 1780589106.0, "num_crossposts": 0, "mod_reports": [], "is_video": false}}], "before": null}}, {"kind": "Listing", "data": {"after": null, "dist": null, "modhash": "", "geo_filter": "", "children": [{"kind": "t1", "data": {"subreddit_id": "t5_2qh0y", "approved_at_utc": null, "author_is_blocked": false, "comment_type": null, "awarders": [], "mod_reason_by": null, "banned_by": null, "author_flair_type": "text", "total_awards_received": 0, "subreddit": "Python", "author_flair_template_id": null, "likes": null, "replies": "", "user_reports": [], "saved": false, "id": "oprc6qa", "banned_at_utc": null, "mod_reason_title": null, "gilded": 0, "archived": false, "collapsed_reason_code": null, "no_follow": true, "author": "hannah_G_", "can_mod_post": false, "created_utc": 1780597457.0, "send_replies": true, "parent_id": "t3_1tws1w7", "score": 4, "author_fullname": "t2_gjk10lou", "approved_by": null, "mod_note": null, "all_awardings": [], "collapsed": false, "body": "**db-git**\u00a0\\- keep your local database in sync with your git branches.\n\n# What My Project Does\n\n`db-git`\u00a0is a developer tool for projects where database state follows code changes: schema migrations, seed data, experimental feature work, and branch switching during reviews. It installs git\u00a0`post-checkout`\u00a0hook and keeps your local database aligned with the branch you are working on.\n\n* Two workflows:\n * `shared`: one database, saved and restored per branch\n * `per-branch`: one database per branch\n* PostgreSQL support today, with plans for more database backends\n* Two PostgreSQL snapshot strategies:\n * `template`: fast database clones using\u00a0`CREATE DATABASE ... TEMPLATE`\n * `pgdump`: portable snapshots using\u00a0`pg_dump`\u00a0and\u00a0`pg_restore`\n\n# Target Audience\n\nBackend and full-stack developers who run databases locally and switch branches often, especially on projects where migrations or seed data diverge between branches. It's a local development tool.\n\n# Comparison\n\nThe main things that set\u00a0`db-git`\u00a0apart from existing tools are:\n\n1. It lets you choose per project,\u00a0`shared`\u00a0vs\u00a0`per-branch`, and\u00a0`template`\u00a0vs\u00a0`pgdump`.\n2. It ties database state directly to checkout.\n3. It is not tied to a specific database engine. PostgreSQL is the first supported backend, but the design isn't Postgres-specific, and more databases are planned.\n\n`uv tool install db-git`\n\nGitHub:\u00a0[https://github.com/earthcomfy/db-git](https://github.com/earthcomfy/db-git)\n\nAny feedback is very welcome!", "edited": false, "top_awarded_type": null, "author_flair_css_class": null, "name": "t1_oprc6qa", "is_submitter": false, "downs": 0, "author_flair_richtext": [], "author_patreon_flair": false, "body_html": "

db-git\u00a0- keep your local database in sync with your git branches.

\n\n

What My Project Does

\n\n

db-git\u00a0is a developer tool for projects where database state follows code changes: schema migrations, seed data, experimental feature work, and branch switching during reviews. It installs git\u00a0post-checkout\u00a0hook and keeps your local database aligned with the branch you are working on.

\n\n\n\n

Target Audience

\n\n

Backend and full-stack developers who run databases locally and switch branches often, especially on projects where migrations or seed data diverge between branches. It's a local development tool.

\n\n

Comparison

\n\n

The main things that set\u00a0db-git\u00a0apart from existing tools are:

\n\n
    \n
  1. It lets you choose per project,\u00a0shared\u00a0vs\u00a0per-branch, and\u00a0template\u00a0vs\u00a0pgdump.
  2. \n
  3. It ties database state directly to checkout.
  4. \n
  5. It is not tied to a specific database engine. PostgreSQL is the first supported backend, but the design isn't Postgres-specific, and more databases are planned.
  6. \n
\n\n

uv tool install db-git

\n\n

GitHub:\u00a0https://github.com/earthcomfy/db-git

\n\n

Any feedback is very welcome!

\n
", "removal_reason": null, "collapsed_reason": null, "distinguished": null, "associated_award": null, "stickied": false, "author_premium": false, "can_gild": false, "gildings": {}, "unrepliable_reason": null, "author_flair_text_color": null, "score_hidden": false, "permalink": "/r/Python/comments/1tws1w7/showcase_thread/oprc6qa/", "subreddit_type": "public", "locked": false, "report_reasons": null, "created": 1780597457.0, "author_flair_text": null, "treatment_tags": [], "link_id": "t3_1tws1w7", "subreddit_name_prefixed": "r/Python", "controversiality": 0, "depth": 0, "author_flair_background_color": null, "collapsed_because_crowd_control": null, "mod_reports": [], "num_reports": null, "ups": 4}}, {"kind": "t1", "data": {"subreddit_id": "t5_2qh0y", "approved_at_utc": null, "author_is_blocked": false, "comment_type": null, "awarders": [], "mod_reason_by": null, "banned_by": null, "author_flair_type": "text", "total_awards_received": 0, "subreddit": "Python", "author_flair_template_id": null, "likes": null, "replies": "", "user_reports": [], "saved": false, "id": "opt03ob", "banned_at_utc": null, "mod_reason_title": null, "gilded": 0, "archived": false, "collapsed_reason_code": null, "no_follow": true, "author": "emnoleg", "can_mod_post": false, "created_utc": 1780615070.0, "send_replies": true, "parent_id": "t3_1tws1w7", "score": 3, "author_fullname": "t2_25q8p7gsgg", "approved_by": null, "mod_note": null, "all_awardings": [], "collapsed": false, "body": "# Tired of screen-sharing 3D models in meetings, so I made them float on my webcam instead\n\n \nDrop any\u00a0*.glb*\u00a0file in a folder, pick it from the tray icon, and it appears on your webcam. **Move it, rotate it, scale it**. Your meeting app sees it as a normal camera. Nothing else to open or manage.\n\nGood for product demos, design reviews, showing off Blender exports, branded content on calls. Anything where you want the model visible **without screen-sharing**.\n\nWorks in Zoom, Meet, Teams, Discord, pretty much anything that accepts a webcam input.\n\nRenders the 3D layer **offscreen** and caches it. The model only re-renders when you move it, so the webcam stays smooth on any machine. Python,\u00a0*pyrender*,\u00a0*pyvirtualcam*\u00a0under the hood.\u00a0Open source, setup is one script.\n\n[Project Link](https://github.com/aadi-joshi/cam3)\n\n\n\n*Demo model: V1 from ULTRAKILL on Sketchfab (CC BY). Character by Hakita / New Blood Interactive. Not included in the repo.*\u00a0[*https://sketchfab.com/3d-models/v1-ultrakill-d951a08a8f50412d84e262bad887b285*](https://sketchfab.com/3d-models/v1-ultrakill-d951a08a8f50412d84e262bad887b285)", "edited": false, "top_awarded_type": null, "author_flair_css_class": null, "name": "t1_opt03ob", "is_submitter": false, "downs": 0, "author_flair_richtext": [], "author_patreon_flair": false, "body_html": "

Tired of screen-sharing 3D models in meetings, so I made them float on my webcam instead

\n\n

Drop any\u00a0.glb\u00a0file in a folder, pick it from the tray icon, and it appears on your webcam. Move it, rotate it, scale it. Your meeting app sees it as a normal camera. Nothing else to open or manage.

\n\n

Good for product demos, design reviews, showing off Blender exports, branded content on calls. Anything where you want the model visible without screen-sharing.

\n\n

Works in Zoom, Meet, Teams, Discord, pretty much anything that accepts a webcam input.

\n\n

Renders the 3D layer offscreen and caches it. The model only re-renders when you move it, so the webcam stays smooth on any machine. Python,\u00a0pyrender,\u00a0pyvirtualcam\u00a0under the hood.\u00a0Open source, setup is one script.

\n\n

Project Link

\n\n

Demo model: V1 from ULTRAKILL on Sketchfab (CC BY). Character by Hakita / New Blood Interactive. Not included in the repo.\u00a0https://sketchfab.com/3d-models/v1-ultrakill-d951a08a8f50412d84e262bad887b285

\n
", "removal_reason": null, "collapsed_reason": null, "distinguished": null, "associated_award": null, "stickied": false, "author_premium": false, "can_gild": false, "gildings": {}, "unrepliable_reason": null, "author_flair_text_color": null, "score_hidden": false, "permalink": "/r/Python/comments/1tws1w7/showcase_thread/opt03ob/", "subreddit_type": "public", "locked": false, "report_reasons": null, "created": 1780615070.0, "author_flair_text": null, "treatment_tags": [], "link_id": "t3_1tws1w7", "subreddit_name_prefixed": "r/Python", "controversiality": 0, "depth": 0, "author_flair_background_color": null, "collapsed_because_crowd_control": null, "mod_reports": [], "num_reports": null, "ups": 3}}, {"kind": "t1", "data": {"subreddit_id": "t5_2qh0y", "approved_at_utc": null, "author_is_blocked": false, "comment_type": null, "awarders": [], "mod_reason_by": null, "banned_by": null, "author_flair_type": "text", "total_awards_received": 0, "subreddit": "Python", "author_flair_template_id": null, "likes": null, "replies": "", "user_reports": [], "saved": false, "id": "oqcmdwf", "banned_at_utc": null, "mod_reason_title": null, "gilded": 0, "archived": false, "collapsed_reason_code": null, "no_follow": true, "author": "Comfortable-Noise144", "can_mod_post": false, "created_utc": 1780872157.0, "send_replies": true, "parent_id": "t3_1tws1w7", "score": 3, "author_fullname": "t2_7qhbipym", "approved_by": null, "mod_note": null, "all_awardings": [], "collapsed": false, "body": "Hi,\n\n**I built a VS Code extension to helt prevent losing track of complex math expressions in Python**\n\nWhen you're writing something like\u00a0`(a * np.sqrt(x**2 + y**2)) / (2 * np.pi * sigma**2)`\u00a0it gets really hard to mentally parse what that formula actually is. In Maple or Mathematica you see a clean equation. In Python you just see a wall of parentheses.\n\nSo I built a VS Code extension that lets you select any expression and instantly renders it as a proper math equation. It supports NumPy, SymPy, SciPy, matrices, integrals, derivatives and more.\n\nThis extension is intended for everyone, beginner programmers as well as experienced programmers, it just meant to give a better overview of math expressions. \n\nFree on the marketplace, search\u00a0**\"Python Expression Visualizer\"**\u00a0in VS Code extensions.\n\nThis is a link to the Github repository: \n[https://github.com/NickG-DK/python-expression-visualizer](https://github.com/NickG-DK/python-expression-visualizer)\n\n \nWould love feedback, as this is my first extension ever.", "edited": false, "top_awarded_type": null, "author_flair_css_class": null, "name": "t1_oqcmdwf", "is_submitter": false, "downs": 0, "author_flair_richtext": [], "author_patreon_flair": false, "body_html": "

Hi,

\n\n

I built a VS Code extension to helt prevent losing track of complex math expressions in Python

\n\n

When you're writing something like\u00a0(a * np.sqrt(x**2 + y**2)) / (2 * np.pi * sigma**2)\u00a0it gets really hard to mentally parse what that formula actually is. In Maple or Mathematica you see a clean equation. In Python you just see a wall of parentheses.

\n\n

So I built a VS Code extension that lets you select any expression and instantly renders it as a proper math equation. It supports NumPy, SymPy, SciPy, matrices, integrals, derivatives and more.

\n\n

This extension is intended for everyone, beginner programmers as well as experienced programmers, it just meant to give a better overview of math expressions.

\n\n

Free on the marketplace, search\u00a0"Python Expression Visualizer"\u00a0in VS Code extensions.

\n\n

This is a link to the Github repository:
\nhttps://github.com/NickG-DK/python-expression-visualizer

\n\n

Would love feedback, as this is my first extension ever.

\n
", "removal_reason": null, "collapsed_reason": null, "distinguished": null, "associated_award": null, "stickied": false, "author_premium": false, "can_gild": false, "gildings": {}, "unrepliable_reason": null, "author_flair_text_color": null, "score_hidden": false, "permalink": "/r/Python/comments/1tws1w7/showcase_thread/oqcmdwf/", "subreddit_type": "public", "locked": false, "report_reasons": null, "created": 1780872157.0, "author_flair_text": null, "treatment_tags": [], "link_id": "t3_1tws1w7", "subreddit_name_prefixed": "r/Python", "controversiality": 0, "depth": 0, "author_flair_background_color": null, "collapsed_because_crowd_control": null, "mod_reports": [], "num_reports": null, "ups": 3}}, {"kind": "t1", "data": {"subreddit_id": "t5_2qh0y", "approved_at_utc": null, "author_is_blocked": false, "comment_type": null, "awarders": [], "mod_reason_by": null, "banned_by": null, "author_flair_type": "text", "total_awards_received": 0, "subreddit": "Python", "author_flair_template_id": null, "likes": null, "replies": "", "user_reports": [], "saved": false, "id": "oprmzm5", "banned_at_utc": null, "mod_reason_title": null, "gilded": 0, "archived": false, "collapsed_reason_code": null, "no_follow": true, "author": "anton273", "can_mod_post": false, "created_utc": 1780600389.0, "send_replies": true, "parent_id": "t3_1tws1w7", "score": 2, "author_fullname": "t2_5n55nn0l", "approved_by": null, "mod_note": null, "all_awardings": [], "collapsed": false, "body": "I built watchpoints (data breakpoints) for PyCharm - lets you break on a value change, not a line. \n \nFree and open source, every developer deserves a great debugging experience. \nLink: [https://plugins.jetbrains.com/plugin/32087-python-watchpoint](https://plugins.jetbrains.com/plugin/32087-python-watchpoint)", "edited": false, "top_awarded_type": null, "author_flair_css_class": null, "name": "t1_oprmzm5", "is_submitter": false, "downs": 0, "author_flair_richtext": [], "author_patreon_flair": false, "body_html": "

I built watchpoints (data breakpoints) for PyCharm - lets you break on a value change, not a line.

\n\n

Free and open source, every developer deserves a great debugging experience.
\nLink: https://plugins.jetbrains.com/plugin/32087-python-watchpoint

\n
", "removal_reason": null, "collapsed_reason": null, "distinguished": null, "associated_award": null, "stickied": false, "author_premium": false, "can_gild": false, "gildings": {}, "unrepliable_reason": null, "author_flair_text_color": null, "score_hidden": false, "permalink": "/r/Python/comments/1tws1w7/showcase_thread/oprmzm5/", "subreddit_type": "public", "locked": false, "report_reasons": null, "created": 1780600389.0, "author_flair_text": null, "treatment_tags": [], "link_id": "t3_1tws1w7", "subreddit_name_prefixed": "r/Python", "controversiality": 0, "depth": 0, "author_flair_background_color": null, "collapsed_because_crowd_control": null, "mod_reports": [], "num_reports": null, "ups": 2}}, {"kind": "t1", "data": {"subreddit_id": "t5_2qh0y", "approved_at_utc": null, "author_is_blocked": false, "comment_type": null, "awarders": [], "mod_reason_by": null, "banned_by": null, "author_flair_type": "text", "total_awards_received": 0, "subreddit": "Python", "author_flair_template_id": null, "likes": null, "replies": "", "user_reports": [], "saved": false, "id": "opro849", "banned_at_utc": null, "mod_reason_title": null, "gilded": 0, "archived": false, "collapsed_reason_code": null, "no_follow": true, "author": "hmoein", "can_mod_post": false, "created_utc": 1780600729.0, "send_replies": true, "parent_id": "t3_1tws1w7", "score": 2, "author_fullname": "t2_jeyhnly", "approved_by": null, "mod_note": null, "all_awardings": [], "collapsed": false, "body": "[Grizzlars](https://github.com/NavodPeiris/grizzlars)\u00a0is Python bindings for the C++ DataFrame with an interface almost identical to Pandas. It is a bit of work in progress. It depends on an older version of C++ DataFrame than the latest release. But it is moving along surely.", "edited": false, "top_awarded_type": null, "author_flair_css_class": null, "name": "t1_opro849", "is_submitter": false, "downs": 0, "author_flair_richtext": [], "author_patreon_flair": false, "body_html": "

Grizzlars\u00a0is Python bindings for the C++ DataFrame with an interface almost identical to Pandas. It is a bit of work in progress. It depends on an older version of C++ DataFrame than the latest release. But it is moving along surely.

\n
", "removal_reason": null, "collapsed_reason": null, "distinguished": null, "associated_award": null, "stickied": false, "author_premium": false, "can_gild": false, "gildings": {}, "unrepliable_reason": null, "author_flair_text_color": null, "score_hidden": false, "permalink": "/r/Python/comments/1tws1w7/showcase_thread/opro849/", "subreddit_type": "public", "locked": false, "report_reasons": null, "created": 1780600729.0, "author_flair_text": null, "treatment_tags": [], "link_id": "t3_1tws1w7", "subreddit_name_prefixed": "r/Python", "controversiality": 0, "depth": 0, "author_flair_background_color": null, "collapsed_because_crowd_control": null, "mod_reports": [], "num_reports": null, "ups": 2}}, {"kind": "t1", "data": {"subreddit_id": "t5_2qh0y", "approved_at_utc": null, "author_is_blocked": false, "comment_type": null, "awarders": [], "mod_reason_by": null, "banned_by": null, "author_flair_type": "text", "total_awards_received": 0, "subreddit": "Python", "author_flair_template_id": null, "likes": null, "replies": {"kind": "Listing", "data": {"after": null, "dist": null, "modhash": "", "geo_filter": "", "children": [{"kind": "more", "data": {"count": 2, "name": "t1_oqtbh24", "id": "oqtbh24", "parent_id": "t1_oprt22n", "depth": 1, "children": ["oqtbh24"]}}], "before": null}}, "user_reports": [], "saved": false, "id": "oprt22n", "banned_at_utc": null, "mod_reason_title": null, "gilded": 0, "archived": false, "collapsed_reason_code": null, "no_follow": true, "author": "em_el_k0b01101011", "can_mod_post": false, "created_utc": 1780602067.0, "send_replies": true, "parent_id": "t3_1tws1w7", "score": 2, "author_fullname": "t2_v8e339ps", "approved_by": null, "mod_note": null, "all_awardings": [], "collapsed": false, "body": "**HyperWeave** is a Python library that generates self-contained SVGs: profile cards, star-history charts, small dashboards, receipts from AI coding sessions, and more. No JS, no external deps. Each one is a single SVG that renders anywhere an image does (GitHub READMEs, Slack, Notion, docs).\n\nDrive it from a CLI, an HTTP API, or an MCP server. It can also pull live data into the artifact, so a card can show a package's real download trend or latest version (PyPI, npm, crates, Hugging Face, arXiv, and a few others) without fetching anything yourself.\n\nThere's a hook for AI coding sessions too: each one ends with a receipt of tokens, cost, and tool calls.\n\nFastAPI + Pydantic + Jinja2 + Typer under the hood.\n\n`pip install hyperweave`\n\nGitHub: https://github.com/InnerAura/hyperweave\n\nPyPI: https://pypi.org/project/hyperweave/\n\nStill early, any feedback welcome. Cheers.", "edited": false, "top_awarded_type": null, "author_flair_css_class": null, "name": "t1_oprt22n", "is_submitter": false, "downs": 0, "author_flair_richtext": [], "author_patreon_flair": false, "body_html": "

HyperWeave is a Python library that generates self-contained SVGs: profile cards, star-history charts, small dashboards, receipts from AI coding sessions, and more. No JS, no external deps. Each one is a single SVG that renders anywhere an image does (GitHub READMEs, Slack, Notion, docs).

\n\n

Drive it from a CLI, an HTTP API, or an MCP server. It can also pull live data into the artifact, so a card can show a package's real download trend or latest version (PyPI, npm, crates, Hugging Face, arXiv, and a few others) without fetching anything yourself.

\n\n

There's a hook for AI coding sessions too: each one ends with a receipt of tokens, cost, and tool calls.

\n\n

FastAPI + Pydantic + Jinja2 + Typer under the hood.

\n\n

pip install hyperweave

\n\n

GitHub: https://github.com/InnerAura/hyperweave

\n\n

PyPI: https://pypi.org/project/hyperweave/

\n\n

Still early, any feedback welcome. Cheers.

\n
", "removal_reason": null, "collapsed_reason": null, "distinguished": null, "associated_award": null, "stickied": false, "author_premium": false, "can_gild": false, "gildings": {}, "unrepliable_reason": null, "author_flair_text_color": null, "score_hidden": false, "permalink": "/r/Python/comments/1tws1w7/showcase_thread/oprt22n/", "subreddit_type": "public", "locked": false, "report_reasons": null, "created": 1780602067.0, "author_flair_text": null, "treatment_tags": [], "link_id": "t3_1tws1w7", "subreddit_name_prefixed": "r/Python", "controversiality": 0, "depth": 0, "author_flair_background_color": null, "collapsed_because_crowd_control": null, "mod_reports": [], "num_reports": null, "ups": 2}}, {"kind": "t1", "data": {"subreddit_id": "t5_2qh0y", "approved_at_utc": null, "author_is_blocked": false, "comment_type": null, "awarders": [], "mod_reason_by": null, "banned_by": null, "author_flair_type": "text", "total_awards_received": 0, "subreddit": "Python", "author_flair_template_id": null, "likes": null, "replies": "", "user_reports": [], "saved": false, "id": "opseoev", "banned_at_utc": null, "mod_reason_title": null, "gilded": 0, "archived": false, "collapsed_reason_code": null, "no_follow": true, "author": "Beginning-Fruit-1397", "can_mod_post": false, "created_utc": 1780608167.0, "send_replies": true, "parent_id": "t3_1tws1w7", "score": 2, "author_fullname": "t2_ndboruet", "approved_by": null, "mod_note": null, "all_awardings": [], "collapsed": false, "body": "If you like itertools, fluent interfaces, Rust Result and Option, or the libraries like returns or more-itertools, check out my project pyochain!\u00a0\n\nSince the last showcase, more code have been moved to Rust which led to substantial performance improvements, and new constructs have been added, notably:\n\n- SliceView, zero copy, efficient view/slice of a Sequence\n- StableSet, a set that keep the original Iterable ordering when created.\n- Deque, pyochain version of collections.deque\u00a0\n\nIt's now as well dependency-free!\n\n\u00a0All the code coming from cytoolz (cython toolz version) has been replaced by the same functionality ported in Rust.\n\nLinks:\n\nGithub:\nhttps://github.com/OutSquareCapital/pyochain\n\nPypi:\nhttps://pypi.org/project/pyochain/\n\nMy last showcase on this sub:\nhttps://www.reddit.com/r/Python/comments/1q61bzg/pyochain_rustlike_iterator_result_and_option_in/\n\nComparison vs similar libraries, where's it's been ranked best choice (the post is NOT from me):\nhttps://www.reddit.com/r/Python/comments/1rj3ct7/comment/o8aordo/?context=3\n", "edited": false, "top_awarded_type": null, "author_flair_css_class": null, "name": "t1_opseoev", "is_submitter": false, "downs": 0, "author_flair_richtext": [], "author_patreon_flair": false, "body_html": "

If you like itertools, fluent interfaces, Rust Result and Option, or the libraries like returns or more-itertools, check out my project pyochain!\u00a0

\n\n

Since the last showcase, more code have been moved to Rust which led to substantial performance improvements, and new constructs have been added, notably:

\n\n\n\n

It's now as well dependency-free!

\n\n

\u00a0All the code coming from cytoolz (cython toolz version) has been replaced by the same functionality ported in Rust.

\n\n

Links:

\n\n

Github:\nhttps://github.com/OutSquareCapital/pyochain

\n\n

Pypi:\nhttps://pypi.org/project/pyochain/

\n\n

My last showcase on this sub:\nhttps://www.reddit.com/r/Python/comments/1q61bzg/pyochain_rustlike_iterator_result_and_option_in/

\n\n

Comparison vs similar libraries, where's it's been ranked best choice (the post is NOT from me):\nhttps://www.reddit.com/r/Python/comments/1rj3ct7/comment/o8aordo/?context=3

\n
", "removal_reason": null, "collapsed_reason": null, "distinguished": null, "associated_award": null, "stickied": false, "author_premium": false, "can_gild": false, "gildings": {}, "unrepliable_reason": null, "author_flair_text_color": null, "score_hidden": false, "permalink": "/r/Python/comments/1tws1w7/showcase_thread/opseoev/", "subreddit_type": "public", "locked": false, "report_reasons": null, "created": 1780608167.0, "author_flair_text": null, "treatment_tags": [], "link_id": "t3_1tws1w7", "subreddit_name_prefixed": "r/Python", "controversiality": 0, "depth": 0, "author_flair_background_color": null, "collapsed_because_crowd_control": null, "mod_reports": [], "num_reports": null, "ups": 2}}, {"kind": "t1", "data": {"subreddit_id": "t5_2qh0y", "approved_at_utc": null, "author_is_blocked": false, "comment_type": null, "awarders": [], "mod_reason_by": null, "banned_by": null, "author_flair_type": "text", "total_awards_received": 0, "subreddit": "Python", "author_flair_template_id": null, "likes": null, "replies": "", "user_reports": [], "saved": false, "id": "oq8egkc", "banned_at_utc": null, "mod_reason_title": null, "gilded": 0, "archived": false, "collapsed_reason_code": null, "no_follow": true, "author": "iliketrains166", "can_mod_post": false, "created_utc": 1780820743.0, "send_replies": true, "parent_id": "t3_1tws1w7", "score": 2, "author_fullname": "t2_6i4840c2", "approved_by": null, "mod_note": null, "all_awardings": [], "collapsed": false, "body": "**peeq: A CLI to investigate Python package metadata, dependencies, vulnerabilities and more**\n\nI work with Python packages as published artifacts a lot: building them from source, inspecting source, applying patches, debugging resolver issues, and checking what actually shipped in an sdist or wheel.\n\nThe information is usually available, but it\u2019s scattered across PyPI metadata, source repos, distribution archives, OSV, resolver output, and other places. Source repos are especially tricky because the main branch often does not match the release I\u2019m investigating.\n\nThat led me to build **peeq** \\- a CLI for inspecting Python package metadata, dependencies, files, and versions from PyPI or private indexes, and known vulnerabilities via OSV, without installing or executing the package being inspected.\n\n\n\n**Links:**\n\nGitHub: [https://github.com/MichaelYochpaz/peeq](https://github.com/MichaelYochpaz/peeq)\n\nDocs: [https://peeq.michaelyo.dev](https://peeq.michaelyo.dev)\n\nPyPI: [https://pypi.org/project/peeq](https://pypi.org/project/peeq)\n\n\n\nExample commands you can try (requires uv):\n\n`uvx peeq info requests --full`\n\n`uvx peeq deps docling --version 2.20.0 --diff 2.30.0`\n\n`uvx peeq cat requests pyproject.toml`\n\n`uvx peeq vulns requests --version 2.31.0`\n\n`uvx peeq conflicts kubernetes==35.0.0a1 kfp==2.16.0`\n\n`uvx peeq why \"flask>=3.0\" -d markupsafe`\n\n\n\npeeq is written for both humans and agents, and ships [with a native Agent Skill](https://peeq.michaelyo.dev/ai-agents/skill/).\n\nWith the skill installed, coding agents can answer package questions by inspecting the published metadata/artifacts themselves instead of guessing from memory or installing packages.\n\nWith peeq's skill installed, you can ask your agent questions in natural language like:\n\n\\- \"Does \\`docling\\` depend on \\`pydantic\\`, and through which path?\"\n\n\\- \"Why can't \\`kubernetes==35.0.0a1\\` be installed together with \\`kfp==2.16.0\\`?\"\n\n\\- \"What changed in \\`docling\\` dependencies between versions 2.20.0 and 2.30.0?\"\n\n\\- \"Which build backend does the \\`httpx\\` Python package use?\"\n\nTransparency note: The project relies heavily on AI coding agents for development. I\u2019m a Python software engineer and the maintainer of the project; design choices, code changes, docs, and releases are all manually reviewed and tested by me.\n\n\n\nFeedback (either here or on GitHub) is welcome!\n\n", "edited": false, "top_awarded_type": null, "author_flair_css_class": null, "name": "t1_oq8egkc", "is_submitter": false, "downs": 0, "author_flair_richtext": [], "author_patreon_flair": false, "body_html": "

peeq: A CLI to investigate Python package metadata, dependencies, vulnerabilities and more

\n\n

I work with Python packages as published artifacts a lot: building them from source, inspecting source, applying patches, debugging resolver issues, and checking what actually shipped in an sdist or wheel.

\n\n

The information is usually available, but it\u2019s scattered across PyPI metadata, source repos, distribution archives, OSV, resolver output, and other places. Source repos are especially tricky because the main branch often does not match the release I\u2019m investigating.

\n\n

That led me to build peeq - a CLI for inspecting Python package metadata, dependencies, files, and versions from PyPI or private indexes, and known vulnerabilities via OSV, without installing or executing the package being inspected.

\n\n

Links:

\n\n

GitHub: https://github.com/MichaelYochpaz/peeq

\n\n

Docs: https://peeq.michaelyo.dev

\n\n

PyPI: https://pypi.org/project/peeq

\n\n

Example commands you can try (requires uv):

\n\n

uvx peeq info requests --full

\n\n

uvx peeq deps docling --version 2.20.0 --diff 2.30.0

\n\n

uvx peeq cat requests pyproject.toml

\n\n

uvx peeq vulns requests --version 2.31.0

\n\n

uvx peeq conflicts kubernetes==35.0.0a1 kfp==2.16.0

\n\n

uvx peeq why "flask>=3.0" -d markupsafe

\n\n

peeq is written for both humans and agents, and ships with a native Agent Skill.

\n\n

With the skill installed, coding agents can answer package questions by inspecting the published metadata/artifacts themselves instead of guessing from memory or installing packages.

\n\n

With peeq's skill installed, you can ask your agent questions in natural language like:

\n\n

- "Does `docling` depend on `pydantic`, and through which path?"

\n\n

- "Why can't `kubernetes==35.0.0a1` be installed together with `kfp==2.16.0`?"

\n\n

- "What changed in `docling` dependencies between versions 2.20.0 and 2.30.0?"

\n\n

- "Which build backend does the `httpx` Python package use?"

\n\n

Transparency note: The project relies heavily on AI coding agents for development. I\u2019m a Python software engineer and the maintainer of the project; design choices, code changes, docs, and releases are all manually reviewed and tested by me.

\n\n

Feedback (either here or on GitHub) is welcome!

\n
", "removal_reason": null, "collapsed_reason": null, "distinguished": null, "associated_award": null, "stickied": false, "author_premium": false, "can_gild": false, "gildings": {}, "unrepliable_reason": null, "author_flair_text_color": null, "score_hidden": false, "permalink": "/r/Python/comments/1tws1w7/showcase_thread/oq8egkc/", "subreddit_type": "public", "locked": false, "report_reasons": null, "created": 1780820743.0, "author_flair_text": null, "treatment_tags": [], "link_id": "t3_1tws1w7", "subreddit_name_prefixed": "r/Python", "controversiality": 0, "depth": 0, "author_flair_background_color": null, "collapsed_because_crowd_control": null, "mod_reports": [], "num_reports": null, "ups": 2}}, {"kind": "t1", "data": {"subreddit_id": "t5_2qh0y", "approved_at_utc": null, "author_is_blocked": false, "comment_type": null, "awarders": [], "mod_reason_by": null, "banned_by": null, "author_flair_type": "text", "total_awards_received": 0, "subreddit": "Python", "author_flair_template_id": null, "likes": null, "replies": "", "user_reports": [], "saved": false, "id": "ot36qxq", "banned_at_utc": null, "mod_reason_title": null, "gilded": 0, "archived": false, "collapsed_reason_code": null, "no_follow": true, "author": "WompTitanium", "can_mod_post": false, "created_utc": 1782115044.0, "send_replies": true, "parent_id": "t3_1tws1w7", "score": 2, "author_fullname": "t2_2agi8wikb3", "approved_by": null, "mod_note": null, "all_awardings": [], "collapsed": false, "body": "Built a CLI tool that maps any codebase instantly, no API keys, fully offline\nJust run pip install codemappr then codemappr scan inside any project folder.\nIt detects 20+ project types (React, Django, Rust, Flutter, etc.) and gives you a full architecture breakdown in seconds. Outputs to terminal, Markdown, or HTML.\nNo setup, no API keys, no internet needed.\nGitHub: https://github.com/erensh27/CodeMappr[codemappr](https://github.com/erensh27/CodeMappr)", "edited": false, "top_awarded_type": null, "author_flair_css_class": null, "name": "t1_ot36qxq", "is_submitter": false, "downs": 0, "author_flair_richtext": [], "author_patreon_flair": false, "body_html": "

Built a CLI tool that maps any codebase instantly, no API keys, fully offline\nJust run pip install codemappr then codemappr scan inside any project folder.\nIt detects 20+ project types (React, Django, Rust, Flutter, etc.) and gives you a full architecture breakdown in seconds. Outputs to terminal, Markdown, or HTML.\nNo setup, no API keys, no internet needed.\nGitHub: https://github.com/erensh27/CodeMappr[codemappr](https://github.com/erensh27/CodeMappr)

\n
", "removal_reason": null, "collapsed_reason": null, "distinguished": null, "associated_award": null, "stickied": false, "author_premium": false, "can_gild": false, "gildings": {}, "unrepliable_reason": null, "author_flair_text_color": null, "score_hidden": false, "permalink": "/r/Python/comments/1tws1w7/showcase_thread/ot36qxq/", "subreddit_type": "public", "locked": false, "report_reasons": null, "created": 1782115044.0, "author_flair_text": null, "treatment_tags": [], "link_id": "t3_1tws1w7", "subreddit_name_prefixed": "r/Python", "controversiality": 0, "depth": 0, "author_flair_background_color": null, "collapsed_because_crowd_control": null, "mod_reports": [], "num_reports": null, "ups": 2}}, {"kind": "t1", "data": {"subreddit_id": "t5_2qh0y", "approved_at_utc": null, "author_is_blocked": false, "comment_type": null, "awarders": [], "mod_reason_by": null, "banned_by": null, "author_flair_type": "text", "total_awards_received": 0, "subreddit": "Python", "author_flair_template_id": null, "likes": null, "replies": "", "user_reports": [], "saved": false, "id": "ops17j6", "banned_at_utc": null, "mod_reason_title": null, "gilded": 0, "archived": false, "collapsed_reason_code": null, "no_follow": true, "author": "iamnotafermiparadox", "can_mod_post": false, "created_utc": 1780604316.0, "send_replies": true, "parent_id": "t3_1tws1w7", "score": 1, "author_fullname": "t2_fd5z8ffe", "approved_by": null, "mod_note": null, "all_awardings": [], "collapsed": false, "body": "MailTriage is a local, batch-oriented IMAP email triage tool. \n\nThis tool allows me to generate an html page of email received over the last 24 hours and see the subject and snippet in a customized order. Priority senders are first, others are next, followed by a list of email sent by systems. Senders that I don't want to see are not listed. \n \nI added the ability to send certain email to a llm to be summarized. Those emails roll into a md file for todos. Once I mark the todo as done, the tool removes that entry and archives it.\n\nBitwarden CLI pull email credentials. Other methods could be used.\n\n[https://github.com/rogdooley/MailTriage](https://github.com/rogdooley/MailTriage)\n\nCodeGuage: CodeGauge is a deterministic, local-first code quality and security analysis platform. I had this built so I could monitor the \"quality\" of LLM generated code based on linters and static analysis tools.\n\n \n[https://github.com/rogdooley/CodeGauge](https://github.com/rogdooley/CodeGauge)", "edited": false, "top_awarded_type": null, "author_flair_css_class": null, "name": "t1_ops17j6", "is_submitter": false, "downs": 0, "author_flair_richtext": [], "author_patreon_flair": false, "body_html": "

MailTriage is a local, batch-oriented IMAP email triage tool.

\n\n

This tool allows me to generate an html page of email received over the last 24 hours and see the subject and snippet in a customized order. Priority senders are first, others are next, followed by a list of email sent by systems. Senders that I don't want to see are not listed.

\n\n

I added the ability to send certain email to a llm to be summarized. Those emails roll into a md file for todos. Once I mark the todo as done, the tool removes that entry and archives it.

\n\n

Bitwarden CLI pull email credentials. Other methods could be used.

\n\n

https://github.com/rogdooley/MailTriage

\n\n

CodeGuage: CodeGauge is a deterministic, local-first code quality and security analysis platform. I had this built so I could monitor the "quality" of LLM generated code based on linters and static analysis tools.

\n\n

https://github.com/rogdooley/CodeGauge

\n
", "removal_reason": null, "collapsed_reason": null, "distinguished": null, "associated_award": null, "stickied": false, "author_premium": false, "can_gild": false, "gildings": {}, "unrepliable_reason": null, "author_flair_text_color": null, "score_hidden": false, "permalink": "/r/Python/comments/1tws1w7/showcase_thread/ops17j6/", "subreddit_type": "public", "locked": false, "report_reasons": null, "created": 1780604316.0, "author_flair_text": null, "treatment_tags": [], "link_id": "t3_1tws1w7", "subreddit_name_prefixed": "r/Python", "controversiality": 0, "depth": 0, "author_flair_background_color": null, "collapsed_because_crowd_control": null, "mod_reports": [], "num_reports": null, "ups": 1}}, {"kind": "t1", "data": {"subreddit_id": "t5_2qh0y", "approved_at_utc": null, "author_is_blocked": false, "comment_type": null, "awarders": [], "mod_reason_by": null, "banned_by": null, "author_flair_type": "text", "total_awards_received": 0, "subreddit": "Python", "author_flair_template_id": null, "likes": null, "replies": {"kind": "Listing", "data": {"after": null, "dist": null, "modhash": "", "geo_filter": "", "children": [{"kind": "more", "data": {"count": 6, "name": "t1_opuqgy8", "id": "opuqgy8", "parent_id": "t1_opt5ogy", "depth": 1, "children": ["opuqgy8"]}}], "before": null}}, "user_reports": [], "saved": false, "id": "opt5ogy", "banned_at_utc": null, "mod_reason_title": null, "gilded": 0, "archived": false, "collapsed_reason_code": null, "no_follow": true, "author": "Charming_Guidance_76", "can_mod_post": false, "created_utc": 1780617021.0, "send_replies": true, "parent_id": "t3_1tws1w7", "score": 1, "author_fullname": "t2_7t4cf11b", "approved_by": null, "mod_note": null, "all_awardings": [], "collapsed": false, "body": "**EDOF, the document toolkit I wish had existed when I started**\n\nThis is one of those \"got fed up, built my own thing\" stories. I make card games, and at work I deal with a lot of document stuff (invoices, certificates, QR labels), and every tool I tried was missing exactly one thing I needed. One had no auto-shrink text. One had no curves. One had nice Photoshop-style effects but you couldn't script it. One couldn't even center text vertically in a box (still bitter about that one). I was tired of duct-taping three tools plus glue code together for every job, so I built EDOF. It took a while. It's on PyPI now.\n\n**What My Project Does**\n\nYou build a document in plain Python, or you open the same file in a visual editor (PyQt6) and drag things around. Both sides read and write the exact same file, so nothing gets lost going back and forth. The part I'm happiest with is that it's literally just `import edof`, so you can drop the whole engine into your own app. The editor I ship is just one program that happens to use it.\n\n import edof\n doc = edof.new(width=210, height=297, title=\"Hello\")\n page = doc.add_page(dpi=300)\n page.add_textbox(15, 15, 180, 12, \"Hello world!\")\n doc.export_pdf(\"hello.pdf\") # vector PDF, no extra deps\n \n\nI mostly use it for batch stuff: feed it a CSV, get a few hundred finished PDFs out. That's how I print my own card games now instead of fighting Photoshop layers at 2am. It does text, images, shapes, paths, QR codes, variables with {placeholders}, the auto-shrink and centering I kept missing elsewhere, and it exports to PDF, PNG, SVG and RTF. It can also read and write Word files now, which I'll get to.\n\n**Target Audience**\n\nMe first, honestly. But also anyone in Python who has to crank out documents (labels, invoices, certificates, cards, batch jobs from data), or who wants a document engine living inside their own app instead of bolting on a separate tool. It's MIT, it's on PyPI, I use it for real work. Fair warning on maturity: the core and the editor are solid, the Word part is new and basic, and tables are half-built, so don't lean on those yet.\n\n**Comparison**\n\nReportLab is great but it's code-only and you place everything by coordinates, there's no visual side to hand anyone. python-docx is perfect if you only ever touch Word. LaTeX is its own universe. And none of the visual tools (InDesign and friends) let you just import them into a Python script. EDOF is the in-between I wanted: write it in code or edit it by hand, same file, and embed it anywhere.\n\nThe Word support nearly broke me, by the way. New and genuine respect for whoever maintains .docx tooling for a living. It's basic both directions for now, and it straight up tells you what it can't carry over instead of silently mangling your document.\n\nRepo's here if you want to poke at it: [https://github.com/DavidSchobl/edof](https://github.com/DavidSchobl/edof) . Happy to answer anything, and I'm genuinely after ideas for what to add next.", "edited": false, "top_awarded_type": null, "author_flair_css_class": null, "name": "t1_opt5ogy", "is_submitter": false, "downs": 0, "author_flair_richtext": [], "author_patreon_flair": false, "body_html": "

EDOF, the document toolkit I wish had existed when I started

\n\n

This is one of those "got fed up, built my own thing" stories. I make card games, and at work I deal with a lot of document stuff (invoices, certificates, QR labels), and every tool I tried was missing exactly one thing I needed. One had no auto-shrink text. One had no curves. One had nice Photoshop-style effects but you couldn't script it. One couldn't even center text vertically in a box (still bitter about that one). I was tired of duct-taping three tools plus glue code together for every job, so I built EDOF. It took a while. It's on PyPI now.

\n\n

What My Project Does

\n\n

You build a document in plain Python, or you open the same file in a visual editor (PyQt6) and drag things around. Both sides read and write the exact same file, so nothing gets lost going back and forth. The part I'm happiest with is that it's literally just import edof, so you can drop the whole engine into your own app. The editor I ship is just one program that happens to use it.

\n\n
import edof\ndoc  = edof.new(width=210, height=297, title="Hello")\npage = doc.add_page(dpi=300)\npage.add_textbox(15, 15, 180, 12, "Hello world!")\ndoc.export_pdf("hello.pdf")   # vector PDF, no extra deps\n
\n\n

I mostly use it for batch stuff: feed it a CSV, get a few hundred finished PDFs out. That's how I print my own card games now instead of fighting Photoshop layers at 2am. It does text, images, shapes, paths, QR codes, variables with {placeholders}, the auto-shrink and centering I kept missing elsewhere, and it exports to PDF, PNG, SVG and RTF. It can also read and write Word files now, which I'll get to.

\n\n

Target Audience

\n\n

Me first, honestly. But also anyone in Python who has to crank out documents (labels, invoices, certificates, cards, batch jobs from data), or who wants a document engine living inside their own app instead of bolting on a separate tool. It's MIT, it's on PyPI, I use it for real work. Fair warning on maturity: the core and the editor are solid, the Word part is new and basic, and tables are half-built, so don't lean on those yet.

\n\n

Comparison

\n\n

ReportLab is great but it's code-only and you place everything by coordinates, there's no visual side to hand anyone. python-docx is perfect if you only ever touch Word. LaTeX is its own universe. And none of the visual tools (InDesign and friends) let you just import them into a Python script. EDOF is the in-between I wanted: write it in code or edit it by hand, same file, and embed it anywhere.

\n\n

The Word support nearly broke me, by the way. New and genuine respect for whoever maintains .docx tooling for a living. It's basic both directions for now, and it straight up tells you what it can't carry over instead of silently mangling your document.

\n\n

Repo's here if you want to poke at it: https://github.com/DavidSchobl/edof . Happy to answer anything, and I'm genuinely after ideas for what to add next.

\n
", "removal_reason": null, "collapsed_reason": null, "distinguished": null, "associated_award": null, "stickied": false, "author_premium": false, "can_gild": false, "gildings": {}, "unrepliable_reason": null, "author_flair_text_color": null, "score_hidden": false, "permalink": "/r/Python/comments/1tws1w7/showcase_thread/opt5ogy/", "subreddit_type": "public", "locked": false, "report_reasons": null, "created": 1780617021.0, "author_flair_text": null, "treatment_tags": [], "link_id": "t3_1tws1w7", "subreddit_name_prefixed": "r/Python", "controversiality": 0, "depth": 0, "author_flair_background_color": null, "collapsed_because_crowd_control": null, "mod_reports": [], "num_reports": null, "ups": 1}}, {"kind": "t1", "data": {"subreddit_id": "t5_2qh0y", "approved_at_utc": null, "author_is_blocked": false, "comment_type": null, "awarders": [], "mod_reason_by": null, "banned_by": null, "author_flair_type": "text", "total_awards_received": 0, "subreddit": "Python", "author_flair_template_id": null, "likes": null, "replies": "", "user_reports": [], "saved": false, "id": "opul15z", "banned_at_utc": null, "mod_reason_title": null, "gilded": 0, "archived": false, "collapsed_reason_code": null, "no_follow": true, "author": "Pytrithon", "can_mod_post": false, "created_utc": 1780636699.0, "send_replies": true, "parent_id": "t3_1tws1w7", "score": 1, "author_fullname": "t2_yzvpcs5sb", "approved_by": null, "mod_note": null, "all_awardings": [], "collapsed": false, "body": "## Introduction\n\nI have already introduced Pytrithon three times on Reddit.\nSee:\n\nhttps://www.reddit.com/r/Python/comments/1q8dwsm/pytrithon_v119_graphical_petri_net_inspired_agent/\nhttps://www.reddit.com/r/Python/comments/1nr3qvm/pytrithon_graphical_petrinet_inspired_agent/\nhttps://www.reddit.com/r/Python/comments/1mx9w5r/graphical_petrinet_inspired_agent_oriented/\n\n## What My Project Does\n\nPytrithon is a graphical Petri net inspired agent oriented programming language based on Python.\nIt allows writing code as a two dimensional graph of interconnected elements and separates data as Places and code as Transitions. Inter Agent communication and GUI widgets are first class components of the language. Through the Monipulator, Agents can be monitored and manipulated.\n\n## Target Audience\n\nThe target audience is both experienced and novice programmers who want to try something new.\n\n## Why I Built It\n\nI realized the power of Petri net inspired programming and the joy of having a more expressive way to specify control flow.\n\n## Comparison\n\nThere are no other visual programming languages which embed actual code into their graphs.\n\n## How To Explore\n\nTo run all included example Agents you need at least Python 3.10 installed. To install all dependencies, run the 'install' script. Then you can start up a Nexus with a Monipulator by running the 'pytrithon' script, where you can start Agents through opening them with 'crtl-o' twice and hitting the 'Open Agent' button. You can also directly specify which Agents to run through the command line by starting a Nexus, Monipulator, and Agents in one single command: 'python nexus -m \\ \\'.\n\nRecommended example Agents to run are: 'basic', 'prodcons', 'address', 'kata', 'calculator', 'kniffel', 'guess', 'yahtzeeserver' + multiple 'yahtzee', 'pokerserver' + multiple 'poker', 'chatserver' + multiple 'chat', 'image', 'jobapplic', and 'nethods'. As a proof of concept, I created a whole Pygame game, TMWOTY2, which is choreographed by 6 Agents as their own processes, which runs at a solid 60 frames per second. To start or open TMWOTY2 in the Monipulator, run the 'tmwoty2' or 'edittmwoty2' script. Your focus should on the 'workbench' folder, which contains all Agents and their respective Python modules; the 'Pytrithon' folder is just the backstage where the magic happens.\n\n## What Is New\n\nSince my last post the whole system now handles Agents, Monipulators, and Nexi terminating from the network. Bookkeeping is performed, cleansing the internal structures handling all process types, making the prototype more resilient. The 'chatserver' and 'chat' Agents now show a list of Agents currently connected. This is enabled through the new 'Event' Transition, which pushes Nexus Events to all listening Agents.\n\nSince my penultimate post I have added a distributed Yahtzee game which you should try out. In order to setup a server on a reachable machine and connect other machines, you need to do the following:\nOn the machine meant to be the server, run 'python nexus yahtzeeserver' first. Then on the machines meant to be the clients through which users play, run 'python nexus -x \\ yahtzee'. The clients probe the interconnected Nexi for a server and start with a lobby mask where you can select your name and start a game with all players signed up.\n\n## GitHub Link\n\nhttps://github.com/JochenSimon/pytrithon\n\n-------\n\nThis is the fifth post about Pytrithon on Reddit. There is a plethora of example Agents to view and run included in the repository.\nPlease check it out and send feedback to the E-Mail address stated in the Monipulator About blurb.\nI plan on putting Pytrithon onto the next level soon. Be sure to check for new happenings.", "edited": false, "top_awarded_type": null, "author_flair_css_class": null, "name": "t1_opul15z", "is_submitter": false, "downs": 0, "author_flair_richtext": [], "author_patreon_flair": false, "body_html": "

Introduction

\n\n

I have already introduced Pytrithon three times on Reddit.\nSee:

\n\n

https://www.reddit.com/r/Python/comments/1q8dwsm/pytrithon_v119_graphical_petri_net_inspired_agent/\nhttps://www.reddit.com/r/Python/comments/1nr3qvm/pytrithon_graphical_petrinet_inspired_agent/\nhttps://www.reddit.com/r/Python/comments/1mx9w5r/graphical_petrinet_inspired_agent_oriented/

\n\n

What My Project Does

\n\n

Pytrithon is a graphical Petri net inspired agent oriented programming language based on Python.\nIt allows writing code as a two dimensional graph of interconnected elements and separates data as Places and code as Transitions. Inter Agent communication and GUI widgets are first class components of the language. Through the Monipulator, Agents can be monitored and manipulated.

\n\n

Target Audience

\n\n

The target audience is both experienced and novice programmers who want to try something new.

\n\n

Why I Built It

\n\n

I realized the power of Petri net inspired programming and the joy of having a more expressive way to specify control flow.

\n\n

Comparison

\n\n

There are no other visual programming languages which embed actual code into their graphs.

\n\n

How To Explore

\n\n

To run all included example Agents you need at least Python 3.10 installed. To install all dependencies, run the 'install' script. Then you can start up a Nexus with a Monipulator by running the 'pytrithon' script, where you can start Agents through opening them with 'crtl-o' twice and hitting the 'Open Agent' button. You can also directly specify which Agents to run through the command line by starting a Nexus, Monipulator, and Agents in one single command: 'python nexus -m <agent1> <agent2>'.

\n\n

Recommended example Agents to run are: 'basic', 'prodcons', 'address', 'kata', 'calculator', 'kniffel', 'guess', 'yahtzeeserver' + multiple 'yahtzee', 'pokerserver' + multiple 'poker', 'chatserver' + multiple 'chat', 'image', 'jobapplic', and 'nethods'. As a proof of concept, I created a whole Pygame game, TMWOTY2, which is choreographed by 6 Agents as their own processes, which runs at a solid 60 frames per second. To start or open TMWOTY2 in the Monipulator, run the 'tmwoty2' or 'edittmwoty2' script. Your focus should on the 'workbench' folder, which contains all Agents and their respective Python modules; the 'Pytrithon' folder is just the backstage where the magic happens.

\n\n

What Is New

\n\n

Since my last post the whole system now handles Agents, Monipulators, and Nexi terminating from the network. Bookkeeping is performed, cleansing the internal structures handling all process types, making the prototype more resilient. The 'chatserver' and 'chat' Agents now show a list of Agents currently connected. This is enabled through the new 'Event' Transition, which pushes Nexus Events to all listening Agents.

\n\n

Since my penultimate post I have added a distributed Yahtzee game which you should try out. In order to setup a server on a reachable machine and connect other machines, you need to do the following:\nOn the machine meant to be the server, run 'python nexus yahtzeeserver' first. Then on the machines meant to be the clients through which users play, run 'python nexus -x <serveraddress> yahtzee'. The clients probe the interconnected Nexi for a server and start with a lobby mask where you can select your name and start a game with all players signed up.

\n\n

GitHub Link

\n\n

https://github.com/JochenSimon/pytrithon

\n\n
\n\n

This is the fifth post about Pytrithon on Reddit. There is a plethora of example Agents to view and run included in the repository.\nPlease check it out and send feedback to the E-Mail address stated in the Monipulator About blurb.\nI plan on putting Pytrithon onto the next level soon. Be sure to check for new happenings.

\n
", "removal_reason": null, "collapsed_reason": null, "distinguished": null, "associated_award": null, "stickied": false, "author_premium": false, "can_gild": false, "gildings": {}, "unrepliable_reason": null, "author_flair_text_color": null, "score_hidden": false, "permalink": "/r/Python/comments/1tws1w7/showcase_thread/opul15z/", "subreddit_type": "public", "locked": false, "report_reasons": null, "created": 1780636699.0, "author_flair_text": null, "treatment_tags": [], "link_id": "t3_1tws1w7", "subreddit_name_prefixed": "r/Python", "controversiality": 0, "depth": 0, "author_flair_background_color": null, "collapsed_because_crowd_control": null, "mod_reports": [], "num_reports": null, "ups": 1}}, {"kind": "t1", "data": {"subreddit_id": "t5_2qh0y", "approved_at_utc": null, "author_is_blocked": false, "comment_type": null, "awarders": [], "mod_reason_by": null, "banned_by": null, "author_flair_type": "text", "total_awards_received": 0, "subreddit": "Python", "author_flair_template_id": null, "likes": null, "replies": "", "user_reports": [], "saved": false, "id": "opuw6vu", "banned_at_utc": null, "mod_reason_title": null, "gilded": 0, "archived": false, "collapsed_reason_code": null, "no_follow": true, "author": "AdHot6282", "can_mod_post": false, "created_utc": 1780642079.0, "send_replies": true, "parent_id": "t3_1tws1w7", "score": 1, "author_fullname": "t2_p6h1483kx", "approved_by": null, "mod_note": null, "all_awardings": [], "collapsed": false, "body": "LocalClicky is a menubar app that lets you control your Mac with your voice, completely offline. \n \n \nSay \"Computer\" to start a session. It stays active - chain commands without repeating the wake word. Say \"bye\" to end. It auto-stops recording when you stop talking (webrtcvad), so there's no fixed timeout. \n \n \nWhat it can do: click things on your screen by name, open/quit apps, control Spotify and volume, create reminders from natural language, run shell commands, inject JS into Chrome. Vision is on-demand \u2014 the model calls look\\_at\\_screen itself when it needs to see something.\n\nOne thing that pushed me to build this: I noticed most people don't think twice before enabling cloud based AI assistants on their machines. But these tools are taking full screenshots of your screen, your code, your emails, your Figma files, your bank statements, your personal moment and sending them to a server. I don't like that at all. LocalClicky's vision model runs locally; screenshots never leave your machine.\n\n \nStack: Python, Whisper.cpp, Ollama (qwen3:8b + gemma4:e4b), webrtcvad, PyAutoGUI, rumps. \n \n \nNothing leaves your machine. MIT licensed, open source. \n \n \nGitHub: [https://github.com/dikshantrajput/LocalClicky](https://github.com/dikshantrajput/LocalClicky) \nDemo: [https://www.youtube.com/watch?v=i8QpFR6nEY4](https://www.youtube.com/watch?v=i8QpFR6nEY4)", "edited": false, "top_awarded_type": null, "author_flair_css_class": null, "name": "t1_opuw6vu", "is_submitter": false, "downs": 0, "author_flair_richtext": [], "author_patreon_flair": false, "body_html": "

LocalClicky is a menubar app that lets you control your Mac with your voice, completely offline.

\n\n

Say "Computer" to start a session. It stays active - chain commands without repeating the wake word. Say "bye" to end. It auto-stops recording when you stop talking (webrtcvad), so there's no fixed timeout.

\n\n

What it can do: click things on your screen by name, open/quit apps, control Spotify and volume, create reminders from natural language, run shell commands, inject JS into Chrome. Vision is on-demand \u2014 the model calls look_at_screen itself when it needs to see something.

\n\n

One thing that pushed me to build this: I noticed most people don't think twice before enabling cloud based AI assistants on their machines. But these tools are taking full screenshots of your screen, your code, your emails, your Figma files, your bank statements, your personal moment and sending them to a server. I don't like that at all. LocalClicky's vision model runs locally; screenshots never leave your machine.

\n\n

Stack: Python, Whisper.cpp, Ollama (qwen3:8b + gemma4:e4b), webrtcvad, PyAutoGUI, rumps.

\n\n

Nothing leaves your machine. MIT licensed, open source.

\n\n

GitHub: https://github.com/dikshantrajput/LocalClicky
\nDemo: https://www.youtube.com/watch?v=i8QpFR6nEY4

\n
", "removal_reason": null, "collapsed_reason": null, "distinguished": null, "associated_award": null, "stickied": false, "author_premium": false, "can_gild": false, "gildings": {}, "unrepliable_reason": null, "author_flair_text_color": null, "score_hidden": false, "permalink": "/r/Python/comments/1tws1w7/showcase_thread/opuw6vu/", "subreddit_type": "public", "locked": false, "report_reasons": null, "created": 1780642079.0, "author_flair_text": null, "treatment_tags": [], "link_id": "t3_1tws1w7", "subreddit_name_prefixed": "r/Python", "controversiality": 0, "depth": 0, "author_flair_background_color": null, "collapsed_because_crowd_control": null, "mod_reports": [], "num_reports": null, "ups": 1}}, {"kind": "more", "data": {"count": 193, "name": "t1_opwgwoi", "id": "opwgwoi", "parent_id": "t3_1tws1w7", "depth": 0, "children": ["opwgwoi", "opwtnqv", "opyqlyr", "oq3bs7r", "opzzs23", "oq1whth", "oq1v3y9", "oq8v60l", "oq8i924", "oq6mjf1", "oq2jzij", "oqg5gfa", "oq3ycth", "oqonmb5", "oqh241n", "oqlbezo", "oqfz79y", "oqeqodc", "oqlraf9", "oqn45re", "oq9f2ol", "oq351b0", "oq82llc", "oqm1yhi", "oqgccc2", "oqm2wyz", "oqmhoy5", "orfatfq", "os57st2", "oqq7go0", "os3iesd", "oqz1f8j", "oqv3m6f", "ordqhi0", "orggusr", "oqg3sxh", "os8fu61", "oqmux4u", "oqsiroa", "orj2t6c", "osdrfxd", "orcrbot", "orl3amm", "os1bujj", "os1bslg", "oq88l8r", "oqa89aj", "oqm3sah", "or1h1i1", "ornjldf", "os1bjka", "ot45yd0", "otcaqvg", "oskwuov", "otm5dr8", "orqkqzh", "oskcn73", "ou05zjc", "osdrrsv", "or2o0hc", "or2wz4i", "ose4mwn", "otik76y", "ou3jtfi", "orayagm", "or48pdm", "or4mymi", "osy66rd", "ouvq47j", "ot2dwjl", "orstatp", "orswnog", "oqgxkc5", "otejpd7", "otzyfkb", "otye4hz", "oqqvklr", "or4fva1", "oryyg7m", "os6vy45", "ormojhi", "osk8x4i", "oslgjd1", "oswij3d", "ounqnaf", "oswi1ha", "os0emx6", "osay6i5", "ou4qsxk", "osjsmlw", "oujmvmv", "ouzdhfb", "orhhvzi", "oqa9y6c", "or780cu", "orou62e", "orz37b3", "oruz6fi", "otay7sy", "otptzzv", "os6yr4u", "os1bvxu", "oth1uto", "ova1vbj", "ou6v9t9", "otcgma0", "ouhufmq", "ouktsbw", "ouus4d8", "ou4vz0t", "otrro6f", "ouj22j2", "oukezil", "otnkxz0", "ouwrnax", "ouo4rtt", "ouaa4g9", "osqbpid", "ostr6h1", "ot2qz8l", "ory8egy", "otikk0d", "oul28wi", "otibuj8", "otx91u2", "oucx7sc", "ouzhogi", "ov32np3", "oubafil", "orsrjeo", "orlwbju", "orm9g8l", "os1o62h", "os6k48f", "ouq2dja", "otx9qa4", "ouz7ekk", "opskei3", "ovf2cnm", "otr48db", "oupjpg4", "oukhre1", "ovhhem5", "ospxx2g", "orrxvux", "orcjorb", "ouxhgeu", "ouzgjhg", "ouagbv9", "ouiiv9w", "oukwgbi", "ov4z1m4", "oqzmh06", "oqs64e4", "orrzi6i", "ork3l7k", "oshwp5h", "otc4w9v", "otl0juz", "ovajat5", "or9m71i", "osg9pq0", "oube17h", "ouu84r1", "ouvs7p4", "ovc3kpi", "oup0ukf", "oprodsc", "oprsgod", "ot4i9w4", "otcj6nf", "ot44xc7", "os6ph8i", "oslz59n", "osln80c", "ouqxogi", "ou59piq"]}}], "before": null}}] \ No newline at end of file