@@ -132,6 +132,57 @@ func checkPackageInFile(filePath string, projectType ProjectType, pythonMinVersi
132132 return VersionCheckResult {Error : fmt .Errorf ("unsupported file type: %s" , fileName )}
133133}
134134
135+ // parsePythonPackageVersion parses a Python package line and extracts the version
136+ func parsePythonPackageVersion (line string ) (string , bool ) {
137+ // match with optional extras and version specifiers
138+ pattern := regexp .MustCompile (`(?i)^livekit-agents(?:\[[^\]]+\])?\s*([=~><!]+)?\s*([^#]+)?` )
139+ matches := pattern .FindStringSubmatch (line )
140+ if matches == nil {
141+ return "" , false
142+ }
143+
144+ // get the operator (==, >=, etc.) and the version
145+ operator := matches [1 ]
146+ version := strings .TrimSpace (matches [2 ])
147+
148+ if version == "" {
149+ // no version specified means latest
150+ return "latest" , true
151+ }
152+
153+ // clean up the version string if it contains multiple constraints
154+ // handle comma-separated version constraints like ">=1.2.5,<2"
155+ if strings .Contains (version , "," ) {
156+ parts := strings .Split (version , "," )
157+ for _ , part := range parts {
158+ trimmed := strings .TrimSpace (part )
159+ if regexp .MustCompile (`\d` ).MatchString (trimmed ) {
160+ if strings .ContainsAny (trimmed , "=~><" ) {
161+ version = trimmed
162+ } else if operator != "" {
163+ version = operator + trimmed
164+ } else {
165+ version = trimmed
166+ }
167+ break
168+ }
169+ }
170+ } else {
171+ // handle space-separated constraints
172+ firstPart := strings .Split (version , " " )[0 ]
173+ // output expects operator, so we'll preserve or add it
174+ if strings .ContainsAny (firstPart , "=~><" ) {
175+ version = firstPart
176+ } else if operator != "" {
177+ version = operator + firstPart
178+ } else {
179+ version = firstPart
180+ }
181+ }
182+
183+ return version , true
184+ }
185+
135186// checkRequirementsFile checks for livekit-agents in requirements.txt
136187func checkRequirementsFile (filePath , minVersion string ) VersionCheckResult {
137188 content , err := os .ReadFile (filePath )
@@ -146,15 +197,8 @@ func checkRequirementsFile(filePath, minVersion string) VersionCheckResult {
146197 continue
147198 }
148199
149- // Match livekit-agents with optional extras and version specifiers
150- pattern := regexp .MustCompile (`(?i)^livekit-agents(?:\[[^\]]+\])?\s*([=~><!]+)?\s*([^#\s]+)?` )
151- matches := pattern .FindStringSubmatch (line )
152- if matches != nil {
153- version := strings .TrimSpace (matches [2 ])
154- if version == "" {
155- version = "latest" // No version specified means latest
156- }
157-
200+ version , found := parsePythonPackageVersion (line )
201+ if found {
158202 satisfied , err := isVersionSatisfied (version , minVersion )
159203 return VersionCheckResult {
160204 PackageInfo : PackageInfo {
@@ -191,14 +235,8 @@ func checkPyprojectToml(filePath, minVersion string) VersionCheckResult {
191235 if deps , ok := project ["dependencies" ].([]any ); ok {
192236 for _ , dep := range deps {
193237 if line , ok := dep .(string ); ok {
194- pattern := regexp .MustCompile (`(?i)^livekit-agents(?:\[[^\]]+\])?\s*([=~><!]+)?\s*([^#\s]+)?` )
195- matches := pattern .FindStringSubmatch (line )
196- if matches != nil {
197- version := strings .TrimSpace (matches [2 ])
198- if version == "" {
199- version = "latest"
200- }
201-
238+ version , found := parsePythonPackageVersion (line )
239+ if found {
202240 satisfied , err := isVersionSatisfied (version , minVersion )
203241 return VersionCheckResult {
204242 PackageInfo : PackageInfo {
@@ -264,35 +302,37 @@ func checkSetupPy(filePath, minVersion string) VersionCheckResult {
264302
265303 // Look for install_requires or dependencies
266304 patterns := []* regexp.Regexp {
267- regexp .MustCompile (`(?i)install_requires\s*=\s*\[(. *?)\]` ),
268- regexp .MustCompile (`(?i)dependencies\s*=\s*\[(. *?)\]` ),
305+ regexp .MustCompile (`(?i)install_requires\s*=\s*\[([\s\S] *?)\]` ),
306+ regexp .MustCompile (`(?i)dependencies\s*=\s*\[([\s\S] *?)\]` ),
269307 }
270308
271309 for _ , pattern := range patterns {
272310 matches := pattern .FindStringSubmatch (string (content ))
273311 if matches != nil {
274312 depsSection := matches [1 ]
275- // Parse the dependencies section
276- depPattern := regexp .MustCompile (`(?i)["']livekit-agents(?:\[[^\]]+\])?\s*([=~><!]+)?\s*([ ^"'\s ]+)?["']` )
313+ // extract the livekit-agents dependency line
314+ depPattern := regexp .MustCompile (`(?i)["']livekit-agents(?:\[[^\]]+\])?([ ^"']+)?["']` )
277315 depMatches := depPattern .FindStringSubmatch (depsSection )
278316 if depMatches != nil {
279- version := strings . TrimSpace ( depMatches [ 2 ])
280- if version = = "" {
281- version = "latest"
317+ packageLine := "livekit-agents"
318+ if depMatches [ 1 ] ! = "" {
319+ packageLine += depMatches [ 1 ]
282320 }
283-
284- satisfied , err := isVersionSatisfied (version , minVersion )
285- return VersionCheckResult {
286- PackageInfo : PackageInfo {
287- Name : "livekit-agents" ,
288- Version : version ,
289- FoundInFile : filePath ,
290- ProjectType : ProjectTypePythonPip ,
291- Ecosystem : "pypi" ,
292- },
293- MinVersion : minVersion ,
294- Satisfied : satisfied ,
295- Error : err ,
321+ version , found := parsePythonPackageVersion (packageLine )
322+ if found {
323+ satisfied , err := isVersionSatisfied (version , minVersion )
324+ return VersionCheckResult {
325+ PackageInfo : PackageInfo {
326+ Name : "livekit-agents" ,
327+ Version : version ,
328+ FoundInFile : filePath ,
329+ ProjectType : ProjectTypePythonPip ,
330+ Ecosystem : "pypi" ,
331+ },
332+ MinVersion : minVersion ,
333+ Satisfied : satisfied ,
334+ Error : err ,
335+ }
296336 }
297337 }
298338 }
0 commit comments