@@ -107,3 +107,78 @@ def test_single_quoted_values_are_literal():
107107 "ESCAPED_QUOTE" : r"a\"b" ,
108108 }
109109 assert load_dotenv (r'DQ="line1\nline2"' ) == {"DQ" : "line1\n line2" }
110+
111+
112+ def test_hash_in_unquoted_value_is_kept ():
113+ # A "#" only starts an inline comment when preceded by whitespace. A "#" that is part of an
114+ # unquoted value (e.g. in a password, token or URL fragment) must be preserved, not truncated.
115+ data = """
116+ PASSWORD=p@ss#word
117+ TOKEN=abc#123
118+ URL=http://example.com/x#frag
119+ LEADING=#notacomment
120+ COMMENTED=value # actual comment
121+ """
122+ assert load_dotenv (data ) == {
123+ "PASSWORD" : "p@ss#word" ,
124+ "TOKEN" : "abc#123" ,
125+ "URL" : "http://example.com/x#frag" ,
126+ "LEADING" : "#notacomment" ,
127+ "COMMENTED" : "value" ,
128+ }
129+
130+
131+ def test_empty_value_with_inline_comment ():
132+ # Whitespace right after "=" also separates an inline comment: the value is empty, not the
133+ # comment text. Otherwise a comment would leak into env vars/secrets (e.g. `hf jobs --env-file`).
134+ data = """
135+ EMPTY= # comment
136+ EMPTY_MULTI_SPACE= # comment
137+ EMPTY_NO_COMMENT=
138+ LEADING=#notacomment
139+ """
140+ assert load_dotenv (data ) == {
141+ "EMPTY" : "" ,
142+ "EMPTY_MULTI_SPACE" : "" ,
143+ "EMPTY_NO_COMMENT" : "" ,
144+ "LEADING" : "#notacomment" ,
145+ }
146+
147+
148+ def test_comment_attached_to_closing_quote ():
149+ # After a closing quote, a "#" starts a comment even without preceding whitespace.
150+ data = """
151+ DQ="value"# comment
152+ SQ='value'#comment
153+ SPACED="value" # comment
154+ HASH_INSIDE="a#b"
155+ """
156+ assert load_dotenv (data ) == {
157+ "DQ" : "value" ,
158+ "SQ" : "value" ,
159+ "SPACED" : "value" ,
160+ "HASH_INSIDE" : "a#b" ,
161+ }
162+
163+
164+ def test_bare_key_with_inline_comment ():
165+ # A bare key (no "=") is resolved from the environment. A trailing comment must not prevent the
166+ # line from matching, otherwise the key is silently dropped by `--env-file` / `--secrets-file`.
167+ data = """
168+ BARE # comment
169+ BARE_NO_SPACE#comment
170+ BARE_PLAIN
171+ """
172+ environ = {"BARE" : "1" , "BARE_NO_SPACE" : "2" , "BARE_PLAIN" : "3" }
173+ assert load_dotenv (data , environ = environ ) == {"BARE" : "1" , "BARE_NO_SPACE" : "2" , "BARE_PLAIN" : "3" }
174+
175+
176+ def test_invalid_line_does_not_import_from_environ ():
177+ # A key followed by arbitrary text is not a valid line: it must be ignored rather than treated
178+ # as a bare key, which would pull the host value in and clobber an explicit assignment above.
179+ data = """
180+ SECRET=explicit_value
181+ SECRET is documented above
182+ OTHER not an assignment
183+ """
184+ assert load_dotenv (data , environ = {"SECRET" : "HOST_ENV" , "OTHER" : "HOST_ENV" }) == {"SECRET" : "explicit_value" }
0 commit comments