Skip to content
Open
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
24 changes: 7 additions & 17 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,44 +17,34 @@ jobs:
python: ["3"]
os: ["ubuntu-latest"]
include:
- {python: "3.7", os: "ubuntu-22.04"}
- {python: "3.8", os: "ubuntu-22.04"}
- {python: "3.9", os: "ubuntu-22.04"}
- {python: "3.10", os: "ubuntu-22.04"}
- {python: "3.11", os: "ubuntu-22.04"}
- {python: "3.12", os: "ubuntu-22.04"}
- {python: "3.13", os: "ubuntu-24.04"}
- {python: "pypy3.10", os: "ubuntu-24.04"}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: "Set up Python ${{ matrix.python }}"
uses: actions/setup-python@v3
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
- name: "Install dependencies"
run: |
# python -m pip install --upgrade pip
python -m pip install pytest
python -m pip install mock
python -m pip install flake8
python -m pip install importlib_metadata
python -m pip install "setuptools>=62"
python -m pip install wheel
python -m pip install build
- name: "Lint with flake8"
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=80 --statistics
python -m pip install "setuptools>=75"
- name: "Build and test"
run: |
python -m build --no-isolation
pip install dist/dominate*.tar.gz
pytest
pytest --ignore=tests/community
- name: Coveralls
env:
COVERAGE_RCFILE: ".github/workflows/.coveragerc"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
python -m pip install coverage
python -m pip install coveralls
coverage run --source=dominate -m pytest
coverage run --source=dominate -m pytest --ignore=tests/community
python -m coveralls --service=github || true
34 changes: 34 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

# 1. Welcome additions

Anything that is part of the official HTML spec is likely welcome.

Common patterns of web development, or ease-of-use features are welcome, so long as they are general and are likely to be useful to a broad group and not targetting any specific implimentation.

## 1.1. Testing

All PRs must have 100% test coverage of new code.

New features should include example usage, including motivations.



# 2. Not interested

For exceptions to these, see #Community

## 2.2. No 3rd party dependencies

Do not add 3rd party dependencies.

## 2.3. No 3rd party integrations

I am not interested in maintaining integrations with a bunch of random JS/web frameworks/libraries. (i.e. HTMX, Flask, Unpoly, whatever)


# 3. Community Packages

If you wish to add a feature that would otherwise be disallowed by the above, you can make a community package. See `community/htmx.py` for a trivial example.

Community packages must not be referenced from the main library, and must not do anything unless explicitly imported.

2 changes: 1 addition & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
include README.md
include LICENSE.txt
include CONTRIBUTING.md
include pyproject.toml
include setup/setup.py
recursive-include tests *
global-exclude __pycache__
global-exclude *.pyc
9 changes: 3 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
test:
-python2 -m pytest .
python3 -m pytest .
python3 -m pytest . --ignore=tests/community

publish_old: clean test
python3 setup/setup.py sdist
python3 setup/setup.py bdist_wheel
python3 -m twine upload dist/*
test-community:
python3 -m pytest .

publish: clean test
python3 -m build --no-isolation
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -556,15 +556,15 @@ print(d)
Embedding HTML
--------------

If you need to embed a node of pre-formed HTML coming from a library such as markdown or the like, you can avoid escaped HTML by using the raw method from the dominate.util package:
If you need to embed a node of pre-formed HTML coming from a library such as markdown or the like you can avoid escaped HTML by using the raw method from the dominate.util package:

```
from dominate.util import raw
...
td(raw('<a href="example.html">Example</a>'))
```

Without the raw call, this code would render escaped HTML with lt, etc.
Without the raw call, this code would render escaped HTML with lt, etc. The behavior of the previous block of code is the same as `td_element.innerHTML="<a href="example.html">Example</a>"` in JavaScript.


SVG
Expand Down
4 changes: 1 addition & 3 deletions dominate/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
from ._version import __version__
version = __version__

from .version import __version__, version
from .document import document
1 change: 0 additions & 1 deletion dominate/_version.py

This file was deleted.

12 changes: 12 additions & 0 deletions dominate/community/htmx.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

from .. import tags

class HtmxTag:
@classmethod
def clean_attribute(cls, attribute):
attribute = super().clean_attribute(attribute)
if attribute.startswith('hx_'):
attribute = attribute.replace('_', '-')
return attribute

tags.html_tag.__bases__ = (HtmxTag,) + tags.html_tag.__bases__
6 changes: 3 additions & 3 deletions dominate/dom_tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from collections import defaultdict, namedtuple
from functools import wraps
import threading
from asyncio import get_event_loop
from asyncio import get_running_loop
from uuid import uuid4
from contextvars import ContextVar

Expand Down Expand Up @@ -71,7 +71,7 @@ def _get_thread_context():
context.append(("greenlet", greenlet.getcurrent()))

try:
if get_event_loop().is_running():
if get_running_loop().is_running():
# Only add this extra information if we are actually in a running event loop
context.append(("async", _get_async_context_id()))
# A runtime error is raised if there is no async loop...
Expand Down Expand Up @@ -441,7 +441,7 @@ def clean_attribute(attribute):
}.get(attribute, attribute)

# Workaround for Python's reserved words
if attribute[0] == '_':
if attribute[0] == '_' and len(attribute) > 1:
attribute = attribute[1:]

# Workaround for dash
Expand Down
1 change: 1 addition & 0 deletions dominate/version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
version = __version__ = '3.0.0'
16 changes: 8 additions & 8 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
[build-system]
requires = ["setuptools>=62"]
build-backend = "setuptools.build_meta"

[project]
name = "dominate"
description = "Dominate is a Python library for creating and manipulating HTML documents using an elegant DOM API."
Expand All @@ -10,7 +6,7 @@ authors = [
{name = "Tom Flanagan", email = "[email protected]"},
{name = "Jake Wharton"},
]
requires-python = ">=3.4"
requires-python = ">=3.9"
keywords = ["framework", "templating", "template", "html", "xhtml", "python", "html5"]
license = {text = "LGPL-3.0-or-newer"}
classifiers = [
Expand All @@ -19,12 +15,11 @@ classifiers = [
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"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 :: Implementation :: PyPy",
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
"Topic :: Software Development :: Libraries :: Python Modules",
Expand All @@ -36,8 +31,13 @@ dynamic = ["version"]
Homepage = "https://github.com/Knio/dominate"
Source = "https://github.com/Knio/dominate"


[build-system]
requires = ["setuptools>=75"]
build-backend = "setuptools.build_meta"

[tool.setuptools]
packages = ["dominate"]

[tool.setuptools.dynamic]
version = {attr = "dominate._version.__version__"}
version = {attr = "dominate.version.version"}
63 changes: 0 additions & 63 deletions setup/setup.py

This file was deleted.

7 changes: 7 additions & 0 deletions tests/community/test_htmx.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

from dominate import tags
import dominate.community.htmx

def test_hx():
d = tags.div(hx_foo=1)
assert d.render() == '<div hx-foo="1"></div>'
1 change: 1 addition & 0 deletions tests/test_document.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from dominate import document
from dominate.tags import *


def test_doc():
d = document()
assert d.render() == \
Expand Down
5 changes: 1 addition & 4 deletions tests/test_dom_tag.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import pytest
try:
import mock
except ImportError:
import unittest.mock as mock
import unittest.mock as mock

from dominate.tags import *

Expand Down
7 changes: 4 additions & 3 deletions tests/test_dom_tag_async.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from asyncio import gather, run, Semaphore
from dominate.dom_tag import async_context_id
from textwrap import dedent

from dominate import tags
from dominate.dom_tag import async_context_id


# To simulate sleep without making the tests take a hella long time to complete
# lets use a pair of semaphores to explicitly control when our coroutines run.
Expand All @@ -28,7 +29,7 @@ async def merge():
sem_1 = Semaphore(0)
sem_2 = Semaphore(0)
return await gather(
tag_routine_1(sem_1, sem_2),
tag_routine_1(sem_1, sem_2),
tag_routine_2(sem_1, sem_2)
)

Expand Down Expand Up @@ -67,7 +68,7 @@ async def merge():
<div id="2"></div>
</div>
""").strip()

assert tag_2 == dedent("""\
<div id="3">
<div id="4"></div>
Expand Down
2 changes: 1 addition & 1 deletion tests/test_dominate.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

def test_version():
import dominate
version = '2.9.1'
version = '3.0.0'
assert dominate.version == version
assert dominate.__version__ == version
16 changes: 7 additions & 9 deletions tests/test_html.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import dominate
from dominate.tags import *
import pytest
from dominate.util import raw

try:
xrange = xrange
except NameError:
xrange = range
from dominate.tags import *
from dominate.util import raw


def test_arguments():
Expand Down Expand Up @@ -43,7 +38,7 @@ def test_add():
with pytest.raises(ValueError):
d += None
d += 1
d += xrange(2,3)
d += range(2,3)
d += {'id': 'foo'}
assert d.render() == '<div id="foo">12</div>'
assert len(d) == 2
Expand Down Expand Up @@ -208,6 +203,9 @@ def test_attributes():
with pytest.raises(AttributeError):
x = d['id']

with div(_foo='a', _='b') as d:
assert d.attributes.keys() == {'foo', '_'}

with div() as d:
attr(data_test=False)
assert d['data-test'] is False
Expand Down Expand Up @@ -329,7 +327,7 @@ def test_pretty():

assert p('goodbye ', i('cruel'), ' world').render() == \
'''<p>goodbye <i>cruel</i> world</p>'''

assert p('my 1', sup('st'), ' PR').render() == \
'''<p>my 1<sup>st</sup> PR</p>'''

Expand Down
Loading