Merging
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Build distribution 📦 (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Test the built package works basically. (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Publish Python 🐍 distribution 📦 to PyPI (push) Has been cancelled
ChangeDetection.io App Test / lint-code (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-10 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-11 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-12 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-13 (push) Has been cancelled
ChangeDetection.io Container Build Test / Build linux/amd64 (alpine) (push) Has been cancelled
ChangeDetection.io Container Build Test / Build linux/arm64 (alpine) (push) Has been cancelled
ChangeDetection.io Container Build Test / Build linux/amd64 (main) (push) Has been cancelled
ChangeDetection.io Container Build Test / Build linux/arm/v7 (main) (push) Has been cancelled
ChangeDetection.io Container Build Test / Build linux/arm/v8 (main) (push) Has been cancelled
ChangeDetection.io Container Build Test / Build linux/arm64 (main) (push) Has been cancelled

This commit is contained in:
dgtlmoon
2025-10-31 15:46:18 +01:00
parent 61f6bec142
commit 843659d9e9
5 changed files with 23 additions and 34 deletions
+2 -4
View File
@@ -12,8 +12,6 @@ import copy
# Import schemas from __init__.py
from . import schema, schema_create_watch, schema_update_watch, validate_openapi_request
from ..notification_service import CUSTOM_LINEBREAK_PLACEHOLDER
def validate_time_between_check_required(json_data):
"""
@@ -275,14 +273,14 @@ class WatchHistoryDiff(Resource):
import re
if 'html' in output_format:
content = re.sub(
re.escape(CUSTOM_LINEBREAK_PLACEHOLDER) + r'\r?\n?',
r'\r?\n?',
'<br>\\r\\n',
content
)
else:
# texty types
content = re.sub(
re.escape(CUSTOM_LINEBREAK_PLACEHOLDER) + r'\r?\n?',
r'\r?\n?',
'\\r\\n',
content
)
-4
View File
@@ -13,7 +13,6 @@ from changedetectionio.diff import (
CHANGED_INTO_PLACEMARKER_OPEN, CHANGED_INTO_PLACEMARKER_CLOSED
)
from changedetectionio.notification.handler import apply_html_color_to_body
from changedetectionio.notification_service import CUSTOM_LINEBREAK_PLACEHOLDER
from changedetectionio.store import ChangeDetectionStore
from changedetectionio.auth_decorator import login_optionally_required
from changedetectionio import html_tools, diff
@@ -148,8 +147,6 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMe
for _ in range(min(open_count, close_count)):
result = result.replace('&lt;/span&gt;', '</span>', 1)
# Not necessary because the CSS/HTML will lay it out by linefeed
result = result.replace(CUSTOM_LINEBREAK_PLACEHOLDER, '')
return Markup(result)
@views_blueprint.route("/preview/<string:uuid>", methods=['GET'])
@@ -348,7 +345,6 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMe
diff_cell_grid = build_diff_cell_visualizer(content)
content = apply_html_color_to_body(n_body=content)
content = content.replace(CUSTOM_LINEBREAK_PLACEHOLDER, "\n")
offscreen_content = render_template("diff-offscreen-options.html")
output = render_template("diff.html",
+2 -3
View File
@@ -11,7 +11,6 @@ import diff_match_patch as dmp_module
import re
from .tokenizers import TOKENIZERS, tokenize_words_and_html
from ..notification_service import CUSTOM_LINEBREAK_PLACEHOLDER
# Remember! gmail, outlook etc dont support <style> must be inline.
# Gmail: strips <ins> and <del> tags entirely.
@@ -419,7 +418,7 @@ def render_diff(
if patch_format:
patch = difflib.unified_diff(previous_lines, newest_lines)
return CUSTOM_LINEBREAK_PLACEHOLDER.join(patch)
return "\n".join(patch)
rendered_diff = customSequenceMatcher(
before=previous_lines,
@@ -443,7 +442,7 @@ def render_diff(
result.extend(x)
else:
result.append(x)
return CUSTOM_LINEBREAK_PLACEHOLDER.join(result)
return "\n".join(result)
return flatten(rendered_diff)
@@ -96,7 +96,6 @@ def apply_html_color_to_body(n_body: str):
n_body = n_body.replace(CHANGED_INTO_PLACEMARKER_OPEN,
f'<span style="{HTML_CHANGED_INTO_STYLE}" role="note" aria-label="Changed into" title="Changed into">')
n_body = n_body.replace(CHANGED_INTO_PLACEMARKER_CLOSED, f'</span>')
n_body = n_body.replace('\n', f'{CUSTOM_LINEBREAK_PLACEHOLDER}\n')
return n_body
def apply_discord_markdown_to_body(n_body):
@@ -17,7 +17,6 @@ from changedetectionio.diff import (
CHANGED_INTO_PLACEMARKER_OPEN,
CHANGED_INTO_PLACEMARKER_CLOSED
)
from changedetectionio.notification_service import CUSTOM_LINEBREAK_PLACEHOLDER
# mostly
@@ -81,7 +80,7 @@ class TestDiffBuilder(unittest.TestCase):
newest_version_file_contents=after,
patch_format=True)
output = output.replace(CUSTOM_LINEBREAK_PLACEHOLDER, '\n')
output = output.split("\n")
@@ -156,7 +155,7 @@ Line 10"""
# Test with no context
output = diff.render_diff(before, after, include_equal=False, context_lines=0, word_diff=True)
output = output.replace(CUSTOM_LINEBREAK_PLACEHOLDER, '\n')
lines = output.split("\n")
# Should only show changed lines
self.assertEqual(len([l for l in lines if l.strip()]), 2) # Two changed lines
@@ -165,7 +164,7 @@ Line 10"""
# Test with 1 line of context
output = diff.render_diff(before, after, include_equal=False, context_lines=1, word_diff=True)
output = output.replace(CUSTOM_LINEBREAK_PLACEHOLDER, '\n')
lines = [l for l in output.split("\n") if l.strip()]
# Should show changed lines + 1 line before and after each
self.assertIn('Line 3', output) # 1 line before first change
@@ -176,7 +175,7 @@ Line 10"""
# Test with 2 lines of context
output = diff.render_diff(before, after, include_equal=False, context_lines=2, word_diff=True)
output = output.replace(CUSTOM_LINEBREAK_PLACEHOLDER, '\n')
lines = [l for l in output.split("\n") if l.strip()]
# Should show changed lines + 2 lines before and after each
self.assertIn('Line 2', output) # 2 lines before first change
@@ -197,9 +196,7 @@ Line 4"""
# With include_equal=True, context_lines should be ignored
output_with_context = diff.render_diff(before, after, include_equal=True, context_lines=1)
output_with_context = output_with_context.replace(CUSTOM_LINEBREAK_PLACEHOLDER, '\n')
output_without_context = diff.render_diff(before, after, include_equal=True, context_lines=0)
output_without_context = output_without_context.replace(CUSTOM_LINEBREAK_PLACEHOLDER, '\n')
# Both should show all lines
self.assertIn('Line 1', output_with_context)
@@ -218,7 +215,7 @@ Line 4"""
# With case-insensitive, should detect no changes
output = diff.render_diff(before, after, include_equal=False, case_insensitive=True)
output = output.replace(CUSTOM_LINEBREAK_PLACEHOLDER, '\n')
# Should be empty or minimal since texts are equal when ignoring case
lines = [l for l in output.split("\n") if l.strip()]
@@ -231,7 +228,7 @@ Line 4"""
# Case-insensitive should only detect the second line change
output = diff.render_diff(before, after, include_equal=False, case_insensitive=True, word_diff=True)
output = output.replace(CUSTOM_LINEBREAK_PLACEHOLDER, '\n')
# First line should not appear (same when ignoring case)
self.assertNotIn('Hello', output)
@@ -248,7 +245,7 @@ Line 4"""
# Case-insensitive should only highlight the price change
output = diff.render_diff(before, after, include_equal=False, case_insensitive=True, word_diff=True)
output = output.replace(CUSTOM_LINEBREAK_PLACEHOLDER, '\n')
# Inner spans show the changes within the line
self.assertIn(CHANGED_PLACEMARKER_OPEN, output)
@@ -262,13 +259,13 @@ Line 4"""
# Without ignore_junk, should detect whitespace changes
output = diff.render_diff(before, after, include_equal=False, word_diff=True, ignore_junk=False)
output = output.replace(CUSTOM_LINEBREAK_PLACEHOLDER, '\n')
# Should show some difference (whitespace changes)
self.assertTrue(len(output.strip()) > 0, "Should detect whitespace changes when ignore_junk=False")
# With ignore_junk, should ignore whitespace-only changes
output = diff.render_diff(before, after, include_equal=False, word_diff=True, ignore_junk=True)
output = output.replace(CUSTOM_LINEBREAK_PLACEHOLDER, '\n')
lines = [l for l in output.split("\n") if l.strip()]
self.assertEqual(len(lines), 0, "Should ignore whitespace-only changes when ignore_junk=True")
@@ -279,14 +276,14 @@ Line 4"""
# Without ignore_junk, should detect line change
output = diff.render_diff(before, after, include_equal=False, word_diff=False, ignore_junk=False)
output = output.replace(CUSTOM_LINEBREAK_PLACEHOLDER, '\n')
self.assertIn(f'{CHANGED_PLACEMARKER_OPEN}Hello World{CHANGED_PLACEMARKER_CLOSED}', output)
self.assertIn(f'{CHANGED_INTO_PLACEMARKER_OPEN}Hello World{CHANGED_INTO_PLACEMARKER_CLOSED}', output)
# With ignore_junk enabled and word_diff disabled
# When ignore_junk is enabled, whitespace is normalized at line level so lines match
output = diff.render_diff(before, after, include_equal=False, word_diff=False, ignore_junk=True)
output = output.replace(CUSTOM_LINEBREAK_PLACEHOLDER, '\n')
# Lines should be treated as equal
lines = [l for l in output.split("\n") if l.strip()]
self.assertEqual(len(lines), 0, "Should ignore whitespace differences at line level")
@@ -297,7 +294,7 @@ Line 4"""
after = "The quick brown cat"
output = diff.render_diff(before, after, include_equal=False, word_diff=True, ignore_junk=True)
output = output.replace(CUSTOM_LINEBREAK_PLACEHOLDER, '\n')
# Should still detect the word change (fox -> cat)
self.assertIn(f'{REMOVED_PLACEMARKER_OPEN}fox{REMOVED_PLACEMARKER_CLOSED}', output)
self.assertIn(f'{ADDED_PLACEMARKER_OPEN}cat{ADDED_PLACEMARKER_CLOSED}', output)
@@ -310,12 +307,12 @@ Line 4"""
# Without ignore_junk, should detect difference
output = diff.render_diff(before, after, include_equal=False, word_diff=True, ignore_junk=False)
output = output.replace(CUSTOM_LINEBREAK_PLACEHOLDER, '\n')
self.assertTrue(len(output.strip()) > 0, "Should detect tab vs space differences")
# With ignore_junk, should ignore tab/space differences
output = diff.render_diff(before, after, include_equal=False, word_diff=True, ignore_junk=True)
output = output.replace(CUSTOM_LINEBREAK_PLACEHOLDER, '\n')
lines = [l for l in output.split("\n") if l.strip()]
self.assertEqual(len(lines), 0, "Should ignore tab vs space differences when ignore_junk=True")
@@ -325,7 +322,7 @@ Line 4"""
after = "Value: 200 points"
output = diff.render_diff(before, after, include_equal=False, word_diff=True, ignore_junk=True)
output = output.replace(CUSTOM_LINEBREAK_PLACEHOLDER, '\n')
# Should only highlight the actual value change
self.assertIn(f'{REMOVED_PLACEMARKER_OPEN}100{REMOVED_PLACEMARKER_CLOSED}', output)
self.assertIn(f'{ADDED_PLACEMARKER_OPEN}200{ADDED_PLACEMARKER_CLOSED}', output)
@@ -339,20 +336,20 @@ Line 4"""
# Both enabled: should ignore case and whitespace
output = diff.render_diff(before, after, include_equal=False, word_diff=True,
case_insensitive=True, ignore_junk=True)
output = output.replace(CUSTOM_LINEBREAK_PLACEHOLDER, '\n')
lines = [l for l in output.split("\n") if l.strip()]
self.assertEqual(len(lines), 0, "Should ignore both case and whitespace differences")
# Only case_insensitive: should detect whitespace changes
output = diff.render_diff(before, after, include_equal=False, word_diff=True,
case_insensitive=True, ignore_junk=False)
output = output.replace(CUSTOM_LINEBREAK_PLACEHOLDER, '\n')
self.assertTrue(len(output.strip()) > 0, "Should detect whitespace changes")
# Only ignore_junk: should detect case changes
output = diff.render_diff(before, after, include_equal=False, word_diff=True,
case_insensitive=False, ignore_junk=True)
output = output.replace(CUSTOM_LINEBREAK_PLACEHOLDER, '\n')
# Should detect case differences
self.assertIn('QUICK', output)
self.assertIn('quick', output)
@@ -375,7 +372,7 @@ Line 3 with tabs and spaces"""
# With ignore_junk, should only show unchanged line when include_equal=True
output = diff.render_diff(before, after, include_equal=False, word_diff=True, ignore_junk=True)
output = output.replace(CUSTOM_LINEBREAK_PLACEHOLDER, '\n')
lines = [l for l in output.split("\n") if l.strip()]
# Should be empty since only whitespace changed
self.assertEqual(len(lines), 0, "Should ignore whitespace changes across multiple lines")