Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 20 additions & 39 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,60 +17,39 @@ jobs:
strategy:
matrix:
# https://github.com/actions/python-versions/blob/main/versions-manifest.json
python-version: [3.9, "3.10", "3.11", "3.12", "3.13.0-beta.3"]
python-version: ["3.12", "3.13", "3.14"]
django-version:
- "Django>=4.2,<5.0"
- "Django>=5.0,<5.1"
- "Django==5.1b1"
exclude:
- django-version: "Django>=5.0,<5.1"
python-version: 3.9
- django-version: "Django==5.1b1"
python-version: 3.9
- "Django>=5.2,<6.0"
- "Django>=6.0,<6.1"
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
if: "!endsWith(matrix.python-version, '-dev')"
- uses: actions/checkout@v6
- name: Install uv and set the Python version
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
with:
python-version: ${{ matrix.python-version }}
cache: "pip"
cache-dependency-path: "pyproject.toml"
- name: Install deps
run: |
python -m pip install -e .[test]
python -m pip install "${{ matrix.django-version }}" ${{ matrix.drf }}
- run: pytest
uv add "${{ matrix.django-version }}"
- run: uv run pytest

lint:
runs-on: ubuntu-latest
timeout-minutes: 10
env:
PYTHONPATH: "src"
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: "pip"
cache-dependency-path: "pyproject.toml"
- uses: actions/cache@v4
with:
path: ~/.cache/pre-commit
key: pre-commit|${{ env.pythonLocation }}|${{ hashFiles('.pre-commit-config.yaml') }}
- run: python -m pip install -e .[dev]
- run: pre-commit run --show-diff-on-failure --color=always --all-files
- uses: actions/checkout@v6
- name: Install uv and set the Python version
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
- run: uv run pre-commit run --show-diff-on-failure --color=always --all-files

package:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: "pip"
cache-dependency-path: "pyproject.toml"
uses: actions/setup-python@v6
- name: Install dependencies
run: |
python -m pip install hatch
Expand All @@ -92,7 +71,7 @@ jobs:
id-token: write
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Set release env
id: release_output
run: |
Expand All @@ -107,9 +86,9 @@ jobs:
echo "::set-output name=VERSION::${VERSION}"
echo "::set-output name=BODY::${BODY}"
- name: Setup Python
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: "3.12"
python-version: "3.13"
- name: Download dist
uses: actions/download-artifact@v4
with:
Expand All @@ -125,4 +104,6 @@ jobs:
name: Release ${{ steps.release_output.outputs.VERSION }}
body: ${{ steps.release_output.outputs.BODY }}
draft: false
prerelease: ${{ contains(steps.release_output.outputs.VERSION, 'rc') || contains(steps.release_output.outputs.VERSION, 'b') || contains(steps.release_output.outputs.VERSION, 'a') }}
prerelease: ${{ contains(steps.release_output.outputs.VERSION, 'rc') ||
contains(steps.release_output.outputs.VERSION, 'b') ||
contains(steps.release_output.outputs.VERSION, 'a') }}
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.5.1
rev: v0.15.12
hooks:
- id: ruff
language: system
Expand All @@ -9,7 +9,7 @@ repos:
language: system

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
rev: v6.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

### Unreleased

### 0.1b1

- Drop support for Python 3.9-3.11
- Drop support for Django <5.2

### 0.1a1

- Initial publish
12 changes: 6 additions & 6 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 6 additions & 5 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@
system:
let
pkgs = import nixpkgs { inherit system; };
app-test = pkgs.writeShellScriptBin "app.test" ''pytest $@'';
app-install = pkgs.writeShellScriptBin "app.install" ''uv pip install -e .[dev,test] && pre-commit install'';
app-lint = pkgs.writeShellScriptBin "app.lint" ''pre-commit run -a'';
lib = pkgs.lib;
app-test = pkgs.writeShellScriptBin "app.test" "pytest $@";
app-install = pkgs.writeShellScriptBin "app.install" "uv sync && pre-commit install";
app-lint = pkgs.writeShellScriptBin "app.lint" "pre-commit run -a";
in
{
devShells.default = pkgs.mkShell {
packages = [
pkgs.python312
pkgs.python313
pkgs.uv
pkgs.pyright
];
Expand All @@ -37,7 +38,7 @@
export PYTHONPATH=src;
export DJANGO_SETTINGS_MODULE=tests.settings;
export VIRTUAL_ENV="$(pwd)/.venv"
[[ -d $VIRTUAL_ENV ]] || uv -q venv $VIRTUAL_ENV
[[ -d $VIRTUAL_ENV ]] || ${lib.getExe pkgs.uv} -q venv --python ${lib.getExe pkgs.python313} "$VIRTUAL_ENV"
export PATH="$VIRTUAL_ENV/bin":$PATH
'';
};
Expand Down
21 changes: 8 additions & 13 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ dynamic = ["version"]
description = "Django app to store emails in db"
readme = "README.md"
license = "MIT"
requires-python = ">=3.9"
requires-python = ">=3.12"
authors = [
{ name = "Konstantin Alekseev", email = "mail@kalekseev.com" },
]
Expand All @@ -19,33 +19,33 @@ keywords = [
classifiers = [
"Development Status :: 4 - Beta",
"Environment :: Web Environment",
"Framework :: Django :: 4.2",
"Framework :: Django :: 5.0",
"Framework :: Django :: 5.1",
"Framework :: Django :: 5.2",
"Framework :: Django :: 6.0",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Typing :: Typed",
]
dependencies = [
"django>=4.2",
"django>=5.2",
"django-anymail",
"html2text",
]


[project.optional-dependencies]
[dependency-groups]
dev = [
"django-stubs",
"mypy",
"pdbpp",
"pre-commit",
"ruff",
"ty>=0.0.34",
{ include-group = "test" },
]
test = [
"pytest",
Expand All @@ -68,7 +68,6 @@ packages = ["src/jemail"]

[tool.ruff]
src = ["src"]
target-version = "py39"

[tool.ruff.lint]
select = [
Expand Down Expand Up @@ -97,10 +96,6 @@ addopts = "-p no:doctest --cov=jemail --cov-branch --ds=tests.settings"
django_find_project = false
pythonpath = "."

filterwarnings = [
"ignore:CheckConstraint.check is deprecated.*",
]

[tool.pyright]
include = ["src", "tests"]

Expand Down
2 changes: 1 addition & 1 deletion src/jemail/migrations/0001_initial.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ class Migration(migrations.Migration):
migrations.AddConstraint(
model_name="emailrecipient",
constraint=models.CheckConstraint(
check=models.Q(
condition=models.Q(
("address", django.db.models.functions.text.Lower("address"))
),
name="jemail_address_in_lowercase",
Expand Down
8 changes: 4 additions & 4 deletions src/jemail/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ def create_with_objects(

to, cc, bcc = _fix_email_recipient_duplication(to, cc, bcc)
# optimization to generate html_message path and pass it to create
html_message_path = ""
html_message_path: str | None = ""
if html_message is not None:
_em = EmailMessage()
_em.html_message.save(
Expand Down Expand Up @@ -165,7 +165,7 @@ def send(self, fail_silently: bool = False) -> int:
return result
recipients = {r.address: r for r in self.dbmessage.recipients.all()}
statuses = cast(
dict[str, AnymailRecipientStatus], self.anymail_status.recipients
"dict[str, AnymailRecipientStatus]", self.anymail_status.recipients
)
for address, status in statuses.items():
recipients[address].status = status.status
Expand Down Expand Up @@ -313,7 +313,7 @@ class Meta:
name="jemail_message_has_unique_recipients",
),
models.CheckConstraint(
check=models.Q(address=Lower("address")),
condition=models.Q(address=Lower("address")),
name="jemail_address_in_lowercase",
),
]
Expand Down Expand Up @@ -358,7 +358,7 @@ def fill_from_anymail_event(self, anymail_event: TrackingEventProtocol) -> None:
# generate custom id thus `provider_id` will be empty.
# Write message id from webhook payload `sg_message_id`.
if "sg_message_id" in anymail_event.esp_event:
self.provider_id = anymail_event.esp_event["sg_message_id"]
self.provider_id = anymail_event.esp_event["sg_message_id"] # ty: ignore[invalid-argument-type]


def is_webhook_event_supported(anymail_event: TrackingEventProtocol) -> bool:
Expand Down
2 changes: 1 addition & 1 deletion tests/test_jemail.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@


def from_utc_timestamp(timestamp):
return dt.datetime.fromtimestamp(timestamp, tz=dt.timezone.utc)
return dt.datetime.fromtimestamp(timestamp, tz=dt.UTC)


@pytest.fixture(autouse=True)
Expand Down
1 change: 1 addition & 0 deletions tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def test_create_with_objects(db, mailoutbox):
assert em.subject == "Subject"
assert em.body == "Hi User,..."
assert em.html_message.read() == b"<p>Hi User..."
assert em.html_message.name is not None
assert em.html_message.name.startswith("emails/messages/body")
assert em.reply_to == ["Example Team <support@example.com>"]
assert em.created_by == user
Expand Down
Loading
Loading