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
22 changes: 22 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Lint

on: [push, pull_request, workflow_dispatch]

permissions: {}

env:
FORCE_COLOR: 1
RUFF_OUTPUT_FORMAT: github

jobs:
lint:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-python@v5
with:
python-version: "3.x"
- uses: tox-dev/action-pre-commit-uv@v1
6 changes: 6 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.3
hooks:
- id: ruff
args: [--exit-non-zero-on-fix]
9 changes: 9 additions & 0 deletions .ruff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
fix = true
extend-exclude = [
"*.cgi", # Python 2 code
]
target-version = "py310"

lint.select = [
"W605", # invalid-escape-sequence
]
6 changes: 3 additions & 3 deletions docs-xml/build-html-docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def asText(x):

import re

wsRE = re.compile('\s+')
wsRE = re.compile(r'\s+')

def trimWS(s):
s = wsRE.sub(' ', s)
Expand All @@ -43,7 +43,7 @@ def trimWS(s):

return s

secRe = re.compile("<div id='(\w+)'>\n(.*?\n)</div>\n", re.DOTALL)
secRe = re.compile("<div id='(\\w+)'>\n(.*?\n)</div>\n", re.DOTALL)

import codecs

Expand All @@ -67,7 +67,7 @@ def writeDoc(x, h):


for (sec, txt) in secRe.findall(t):
r = re.compile('<h2>' + sec + '</h2>\s*<div class="docbody">\s*()</div>', re.IGNORECASE)
r = re.compile('<h2>' + sec + r'</h2>\s*<div class="docbody">\s*()</div>', re.IGNORECASE)
idx = r.search(doc).start(1)
doc = doc[:idx] + txt + doc[idx:]

Expand Down
2 changes: 1 addition & 1 deletion docs-xml/mkmsgs.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def buildTestSuite():
if __name__ == '__main__':
import re
for dir, id, msg, html, xml in missing():
msg = re.sub("%\(\w+\)\w?", "<code>foo</code>", msg)
msg = re.sub(r"%\(\w+\)\w?", "<code>foo</code>", msg)
if not path.exists(html):
pass
if not path.exists(xml):
Expand Down
4 changes: 2 additions & 2 deletions src/feedvalidator/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def _validate(aString, firstOccurrenceOnly, loggedEvents, base, encoding, selfUR
from .base import SAXDispatcher
from io import StringIO

if re.match("^\s+<\?xml",aString) and re.search("<generator.*wordpress.*</generator>",aString):
if re.match(r"^\s+<\?xml",aString) and re.search("<generator.*wordpress.*</generator>",aString):
lt = aString.find('<'); gt = aString.find('>')
if lt > 0 and gt > 0 and lt < gt:
loggedEvents.append(logging.WPBlankLine({'line':1,'column':1}))
Expand All @@ -72,7 +72,7 @@ def _validate(aString, firstOccurrenceOnly, loggedEvents, base, encoding, selfUR
# experimental RSS-Profile support
validator.rssCharData = [s.find('&#x')>=0 for s in aString.split('\n')]

xmlver = re.match("^<\?\s*xml\s+version\s*=\s*['\"]([-a-zA-Z0-9_.:]*)['\"]",aString)
xmlver = re.match("^<\\?\\s*xml\\s+version\\s*=\\s*['\"]([-a-zA-Z0-9_.:]*)['\"]",aString)
if xmlver and xmlver.group(1) != '1.0':
validator.log(logging.BadXmlVersion({"version":xmlver.group(1)}))

Expand Down
2 changes: 1 addition & 1 deletion src/feedvalidator/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@

def near_miss(ns):
try:
return re.match(".*\w", ns).group().lower()
return re.match(r".*\w", ns).group().lower()
except:
return ns

Expand Down
10 changes: 5 additions & 5 deletions src/feedvalidator/extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -763,7 +763,7 @@ def validate(self):

class gml_pos(text):
def validate(self):
if not re.match('^[-+]?\d+\.?\d*[ ,][-+]?\d+\.?\d*$', self.value):
if not re.match(r'^[-+]?\d+\.?\d*[ ,][-+]?\d+\.?\d*$', self.value):
return self.log(InvalidCoord({'value':self.value}))
if self.value.find(',')>=0:
self.log(CoordComma({'value':self.value}))
Expand All @@ -785,7 +785,7 @@ def validate(self):
if len(values)<3 or len(values)%2 == 1:
return self.log(InvalidCoordList({'value':self.value}))
for value in values:
if not re.match('^[-+]?\d+\.?\d*$', value):
if not re.match(r'^[-+]?\d+\.?\d*$', value):
return self.log(InvalidCoordList({'value':value}))

class gml_polygon(geo_srsName):
Expand Down Expand Up @@ -1157,21 +1157,21 @@ class g_serviceTypeEnumeration(enumeration):
class g_float(text):
def validate(self):
import re
if not re.match('\d+\.?\d*\s*\w*', self.value):
if not re.match(r'\d+\.?\d*\s*\w*', self.value):
self.log(InvalidFloat({"parent":self.parent.name, "element":self.name,
"attr": ':'.join(self.name.split('_',1)), "value":self.value}))

class floatUnit(text):
def validate(self):
import re
if not re.match('\d+\.?\d*\s*\w*$', self.value):
if not re.match(r'\d+\.?\d*\s*\w*$', self.value):
self.log(InvalidFloatUnit({"parent":self.parent.name, "element":self.name,
"attr": ':'.join(self.name.split('_',1)), "value":self.value}))

class decimal(text):
def validate(self):
import re
if not re.match('[-+]?\d+\.?\d*\s*$', self.value):
if not re.match(r'[-+]?\d+\.?\d*\s*$', self.value):
self.log(InvalidFloatUnit({"parent":self.parent.name, "element":self.name,
"attr": ':'.join(self.name.split('_',1)), "value":self.value}))

Expand Down
2 changes: 1 addition & 1 deletion src/feedvalidator/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def validate(self):
rfc2396_full.validate(self)
import re
ext = self.value.split('.')[-1].lower()
if re.match("^\w+$", ext) and ext not in ['jpg','jpeg','gif','png']:
if re.match(r"^\w+$", ext) and ext not in ['jpg','jpeg','gif','png']:
self.log(ImageUrlFormat({"parent":self.parent.name, "element":self.name}))

class title(nonhtml):
Expand Down
4 changes: 2 additions & 2 deletions src/feedvalidator/kml.py
Original file line number Diff line number Diff line change
Expand Up @@ -1063,7 +1063,7 @@ def validate(self):
self.log(InvalidKmlLatitude({"parent":self.parent.name, "element":self.name, "value":lat}))
# Third coordinate value (altitude) has to be float, if present
if len(point) == 3:
if not re.match('\d+\.?\d*$', point[2]):
if not re.match(r'\d+\.?\d*$', point[2]):
self.log(InvalidFloat({"attr":self.name, "value":point[2]}))

class angle360(text):
Expand All @@ -1079,5 +1079,5 @@ def validate(self):

class FloatWithNegative(text):
def validate(self, name=None):
if not re.match('-?\d+\.?\d*$', self.value):
if not re.match(r'-?\d+\.?\d*$', self.value):
self.log(InvalidFloat({"attr":name or self.name, "value":self.value}))
10 changes: 5 additions & 5 deletions src/feedvalidator/media.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ def validate(self):
nonhtml.validate(self, ContainsUndeclaredHTML)

class media_thumbnail(positiveInteger,rfc2396_full):
npt_re = re.compile("^(now)|(\d+(\.\d+)?)|(\d+:\d\d:\d\d(\.\d+)?)$")
npt_re = re.compile(r"^(now)|(\d+(\.\d+)?)|(\d+:\d\d:\d\d(\.\d+)?)$")
def getExpectedAttrNames(self):
return [(None,'height'),(None,'time'),(None,'url'),(None, 'width')]
def validate(self):
Expand Down Expand Up @@ -295,7 +295,7 @@ def getExpectedAttrNames(self):
]
def validate(self):
self.value = self.attrs.get((None,'bitrate'))
if self.value and not re.match('\d+\.?\d*', self.value):
if self.value and not re.match(r'\d+\.?\d*', self.value):
self.log(InvalidFloat({"parent":self.parent.name, "element":self.name,
"attr": 'bitrate', "value":self.value}))

Expand All @@ -304,7 +304,7 @@ def validate(self):
if self.value: nonNegativeInteger.validate(self)

self.value = self.attrs.get((None,'duration'))
if self.value and not re.match('\d+\.?\d*', self.value):
if self.value and not re.match(r'\d+\.?\d*', self.value):
self.log(InvalidFloat({"parent":self.parent.name, "element":self.name,
"attr": 'duration', "value":self.value}))

Expand All @@ -317,7 +317,7 @@ def validate(self):
if self.value: positiveInteger.validate(self)

self.value = self.attrs.get((None,'framerate'))
if self.value and not re.match('\d+\.?\d*', self.value):
if self.value and not re.match(r'\d+\.?\d*', self.value):
self.log(InvalidFloat({"parent":self.parent.name, "element":self.name,
"attr": 'framerate', "value":self.value}))

Expand All @@ -336,7 +336,7 @@ def validate(self):
self.log(InvalidMediaMedium({"parent":self.parent.name, "element":self.name, "value": self.value}))

self.value = self.attrs.get((None,'samplingrate'))
if self.value and not re.match('\d+\.?\d*', self.value):
if self.value and not re.match(r'\d+\.?\d*', self.value):
self.log(InvalidFloat({"parent":self.parent.name, "element":self.name,
"attr": 'samplingrate', "value":self.value}))

Expand Down
4 changes: 2 additions & 2 deletions src/feedvalidator/opensearch.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def prevalidate(self):
# self.validate_optional_attribute((None,'rel'), text)

class Template(rfc2396_full):
tparam = re.compile("{((?:[-a-zA-Z0-9._~]|%[a-fA-F0-9]{2})+:?(?:[-a-zA-Z0-9._~]|%[a-fA-F0-9]{2})*)\??}")
tparam = re.compile(r"{((?:[-a-zA-Z0-9._~]|%[a-fA-F0-9]{2})+:?(?:[-a-zA-Z0-9._~]|%[a-fA-F0-9]{2})*)\??}")
valuelist = ['searchTerms', 'count', 'startIndex', 'startPage', 'language',
'inputEncoding', 'outputEncoding']

Expand Down Expand Up @@ -127,7 +127,7 @@ def validate(self):
from urllib.parse import quote, unquote
import re
for value in self.value.split():
value = re.sub('%\w\w', lambda x: x.group(0).upper(), value)
value = re.sub(r'%\w\w', lambda x: x.group(0).upper(), value)
if value != quote(unquote(value)):
self.log(NotURLEncoded({}))
break
Expand Down
2 changes: 1 addition & 1 deletion src/feedvalidator/opml.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def do_windowRight(self):
return positiveInteger(), nonblank(), noduplicates()

class commaSeparatedLines(text):
linenumbers_re=re.compile('^(\d+(,\s*\d+)*)?$')
linenumbers_re=re.compile(r'^(\d+(,\s*\d+)*)?$')
def validate(self):
if not self.linenumbers_re.match(self.value):
self.log(InvalidExpansionState({"parent":self.parent.name, "element":self.name, "value":self.value}))
Expand Down
4 changes: 2 additions & 2 deletions src/feedvalidator/uri.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def _qnu(s,safe=''):
return res

# Match an optional port specification
portRe = re.compile(':(\d*)$')
portRe = re.compile(r':(\d*)$')

def _normPort(netloc,defPort):
nl = netloc.lower()
Expand Down Expand Up @@ -146,7 +146,7 @@ def _normPath(p):
return '/'.join([_qnu(c, PCHAR) for c in l])

# From RFC 2396bis, with added end-of-string marker
uriRe = re.compile('^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$')
uriRe = re.compile(r'^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$')

def _canonical(s):
m = uriRe.match(s)
Expand Down
Loading