33# Read: https://stackoverflow.com/questions/176264
44# https://www.rfc-editor.org/rfc/rfc3986#section-3
55
6+ # standard
7+ from urllib .parse import urlsplit
8+
69# local
710from .email import email
11+ from .hostname import hostname
812from .url import url
913from .utils import validator
1014
@@ -21,6 +25,46 @@ def _ipfs_url(value: str):
2125 return True
2226
2327
28+ def _telnet_url (value : str ):
29+ """Validate a telnet URL per RFC 4248.
30+
31+ Ref: https://www.rfc-editor.org/rfc/rfc4248"
32+ Examples:
33+ >>> _telnet_url('telnet://example.com')
34+ True
35+ >>> _telnet_url('telnet://example.com:23')
36+ True
37+ >>> _telnet_url('telnet://example.com:23/')
38+ True
39+
40+ Args:
41+ value:
42+ Telnet URL to validate.
43+
44+ Returns:
45+ (Literal[True]): If `value` is a Telnet URI.
46+ (ValidationError): If `value` is an invalid URI.
47+ """
48+ try :
49+ scheme , netloc , path , query , fragment = urlsplit (value )
50+ except ValueError :
51+ return False
52+
53+ if scheme != "telnet" :
54+ return False
55+ if not netloc :
56+ return False
57+ if query or fragment :
58+ return False
59+ if path and path != "/" :
60+ return False
61+
62+ # handling any additional checks user/pass
63+ if "@" in netloc :
64+ netloc = netloc .rsplit ("@" , 1 )[1 ]
65+ return hostname (netloc , may_have_port = True )
66+
67+
2468@validator
2569def uri (value : str , / ):
2670 """Return whether or not given value is a valid URI.
@@ -60,7 +104,6 @@ def uri(value: str, /):
60104 "rtsp" ,
61105 "sftp" ,
62106 "ssh" ,
63- "telnet" ,
64107 }
65108 # fmt: on
66109 ):
@@ -98,4 +141,8 @@ def uri(value: str, /):
98141 if value .startswith ("urc:" ):
99142 return True
100143
144+ # telnet
145+ if value .startswith ("telnet:" ):
146+ return _telnet_url (value )
147+
101148 return False
0 commit comments