Skip to main content

TagHound: A Python library for managing and evaluating tag rules using scalar and vector operations. Supports YAML and JSON rule loading.

Project description

TagHound

Declarative tagging for Python: write matching rules in YAML or JSON, and TagHound attaches tags to your dicts or whole pandas DataFrames.

Rules stay readable and editable by non-technical users, while your pipeline code stays a one-liner. Typical uses:

  • Categorize bank transactions — regex rules on merchant strings turn a CSV export into budget categories, no ML training required
  • Triage tickets and log events — keyword and threshold rules attach routing tags (severity, team, topic) to each incoming record
  • Enrich scraped datasets — bulk-tag job postings or product listings in a pandas pipeline, then rank matches by rule weights

Installation

Requires Python 3.11+.

pip install taghound

Latest from source: pip install git+https://github.com/rzagreb/TagHound.git

Quick start

Create rules.yml:

- id: food/coffee
  label: Coffee
  weight: 3
  and:
    - key: merchant
      op: "~"
      value: starbucks|blue bottle

- id: alerts/big-purchase
  and:
    - key: amount
      op: ">"
      value: 100

Then:

from taghound import TagHound

th = TagHound.rules_from_yaml("rules.yml")

print(th.find_all_tags({"merchant": "STARBUCKS #1234", "amount": 6.40}))
# ('food/coffee',)
print(th.find_all_tags({"merchant": "Delta Airlines", "amount": 420.00}))
# ('alerts/big-purchase',)

Rule format

A rule is a unique id plus a tree of conditions under and / or, nested as deep as you need:

- id: inventory/tall-tropical-tree  # required, unique; returned as the tag
  label: Tall tropical tree         # optional, defaults to id
  weight: 12                        # optional score, defaults to 0
  info: internal note, not matched  # optional
  and:
    - key: type
      value: tree                   # no `op` means `=`
    - or:
        - key: height
          op: ">"
          value: 20
        - key: location
          op: "~"
          value: tropical

Operators

Op Meaning Value types
= equal (default when op is omitted) int, float, str, bool
!= not equal int, float, str, bool
> < >= <= numeric comparison int, float
in field value is in the list list
not_in field value is not in the list list
~ regex match str or list of str
!~ regex does not match str or list of str

Regex matching is case-insensitive, and a list value is OR-joined (starbucks|blue bottle). Patterns are wrapped in (?<!\w)(?:...)(?!\w) so they match whole words; pass merge_pattern=r"{pattern}" to rules_from_yaml/rules_from_json for raw substring behavior, or any other wrapper with a {pattern} placeholder.

Invalid rules (bad regex, unknown operator) raise at load time, not on first evaluation.

Tagging a DataFrame

For large batches, evaluating a whole DataFrame at once is usually faster than calling find_all_tags per row (the break-even depends on your rules, so measure):

import pandas as pd

df = pd.DataFrame([
    {"merchant": "Blue Bottle Coffee", "amount": 5.75},
    {"merchant": "Delta Airlines", "amount": 420.00},
])

print(th.find_tags_using_vector(df))
#              merchant  amount                   tags
# 0  Blue Bottle Coffee    5.75          [food/coffee]
# 1      Delta Airlines  420.00  [alerts/big-purchase]

The tags column is added to the input DataFrame in place; rename it with output_column_name=. Alternatively, output_format="columns" returns a copy with one boolean column per rule (food/coffee, alerts/big-purchase) — handy for filtering and aggregation.

Scoring and labeling matches

Rule weights and labels are exposed as maps, so ranking matched records is a couple of lines:

tags = th.find_all_tags({"merchant": "STARBUCKS #1234", "amount": 6.40})

score = sum(th.rule_id_to_weight_map[t] for t in tags)
labels = [th.rule_id_to_label_map[t] for t in tags]
print(score, labels)
# 3.0 ['Coffee']

Rules in code

Skip the files entirely by building rules with any Python callable:

from taghound import TagHound
from taghound.models import TagRule

rules = [
    TagRule(
        id="python_rule",
        label="Python",
        weight=10,
        required_fields={"language", "year"},
        scalar_check=lambda d: d["language"] == "python" and d["year"] > 1990,
    )
]

th = TagHound(rules=rules)

JSON works the same as YAML with an identical structure: TagHound.rules_from_json("rules.json").

Example

examples/greek_gods tags a CSV of Greek gods with role/domain rules and prints the resulting DataFrame: uv run python examples/greek_gods/attribute_tags.py

Development

uv sync      # set up the environment
just         # list recipes: test, lint, bench, profile, ...
just check   # lint + tests, same as CI

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

taghound-0.2.0.tar.gz (12.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

taghound-0.2.0-py3-none-any.whl (17.2 kB view details)

Uploaded Python 3

File details

Details for the file taghound-0.2.0.tar.gz.

File metadata

  • Download URL: taghound-0.2.0.tar.gz
  • Upload date:
  • Size: 12.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for taghound-0.2.0.tar.gz
Algorithm Hash digest
SHA256 e2dc6bb82629a869e6559c4afe0099e53c7c95477cdd6cced8f8a28eb3c7dfd4
MD5 7b0377a62c76d2afbe9fbceb59e56e91
BLAKE2b-256 8bf7614668767972f64e2638162885c03b82d60862a83c604e45d422d95a1e00

See more details on using hashes here.

File details

Details for the file taghound-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: taghound-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 17.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for taghound-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 89e1adab269a85a19b14273f3dca2b89c651d55140f6c6ff9aebc34f01fc8aa4
MD5 4abc80cafd499953b403f8601d5366db
BLAKE2b-256 d013efece08a80d08e9d34a05d7e0a2f59ecf67b69580323276f887bedec156a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page