Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-serpent for openSUSE:Factory checked in at 2026-06-28 21:10:43 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-serpent (Old) and /work/SRC/openSUSE:Factory/.python-serpent.new.11887 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-serpent" Sun Jun 28 21:10:43 2026 rev:11 rq:1362156 version:1.43 Changes: -------- --- /work/SRC/openSUSE:Factory/python-serpent/python-serpent.changes 2025-11-10 19:19:11.589003795 +0100 +++ /work/SRC/openSUSE:Factory/.python-serpent.new.11887/python-serpent.changes 2026-06-28 21:12:16.949720927 +0200 @@ -1,0 +2,8 @@ +Sun Jun 28 11:17:11 UTC 2026 - Dirk Müller <[email protected]> + +- update to serpent-1.43: + * Fixed multiple bugs in serialization and parsing (complex + number edge cases, custom types etc) + * Changed java maven publishing method + +------------------------------------------------------------------- Old: ---- serpent-1.42.tar.gz New: ---- serpent-1.43.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-serpent.spec ++++++ --- /var/tmp/diff_new_pack.Q5L1cZ/_old 2026-06-28 21:12:17.521740270 +0200 +++ /var/tmp/diff_new_pack.Q5L1cZ/_new 2026-06-28 21:12:17.521740270 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-serpent # -# Copyright (c) 2025 SUSE LLC and contributors +# Copyright (c) 2026 SUSE LLC and contributors # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,7 +18,7 @@ %{?sle15_python_module_pythons} Name: python-serpent -Version: 1.42 +Version: 1.43 Release: 0 Summary: Serialization based on astliteral_eval License: MIT ++++++ serpent-1.42.tar.gz -> serpent-1.43.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/serpent-1.42/PKG-INFO new/serpent-1.43/PKG-INFO --- old/serpent-1.42/PKG-INFO 2025-10-26 22:58:11.738168200 +0100 +++ new/serpent-1.43/PKG-INFO 2026-05-30 18:30:10.791089300 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: serpent -Version: 1.42 +Version: 1.43 Summary: Serialization based on ast.literal_eval Home-page: https://github.com/irmen/Serpent Author: Irmen de Jong diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/serpent-1.42/dotnet/Serpent/Razorvine.Serpent/ComplexNumber.cs new/serpent-1.43/dotnet/Serpent/Razorvine.Serpent/ComplexNumber.cs --- old/serpent-1.42/dotnet/Serpent/Razorvine.Serpent/ComplexNumber.cs 2025-04-25 12:28:43.000000000 +0200 +++ new/serpent-1.43/dotnet/Serpent/Razorvine.Serpent/ComplexNumber.cs 2026-05-30 16:56:04.000000000 +0200 @@ -22,7 +22,7 @@ { var sb=new StringBuilder(); sb.Append(Real); - if(Imaginary>0) + if(Imaginary>=0 && BitConverter.DoubleToInt64Bits(Imaginary) >= 0) sb.Append('+'); return sb.Append(Imaginary).Append('i').ToString(); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/serpent-1.42/dotnet/Serpent/Razorvine.Serpent/Parser.cs new/serpent-1.43/dotnet/Serpent/Razorvine.Serpent/Parser.cs --- old/serpent-1.42/dotnet/Serpent/Razorvine.Serpent/Parser.cs 2025-04-25 12:28:22.000000000 +0200 +++ new/serpent-1.43/dotnet/Serpent/Razorvine.Serpent/Parser.cs 2026-05-30 16:42:41.000000000 +0200 @@ -93,9 +93,15 @@ // if the last character before the closing parenthesis is a 'j', it is a complex number { int bm = sr.Bookmark(); - string betweenparens = sr.ReadUntil(')', '\n').TrimEnd(); + string betweenparens = sr.ReadUntil(')', '\n'); sr.FlipBack(bm); - return betweenparens.EndsWith("j") ? ParseComplex(sr) : ParseTuple(sr); + string trimmed = betweenparens.Trim(); + if(trimmed.EndsWith("j") && trimmed.IndexOf(',')<0 && (trimmed.IndexOf('(')<0 || trimmed.LastIndexOf('(')==0)) + { + // complex number + return ParseComplex(sr); + } + return ParseTuple(sr); } default: throw new ParseException("invalid sequencetype char"); @@ -650,23 +656,17 @@ private Ast.PrimitiveNode<bool> ParseBool(SeekableStringReader sr) { // True,False - string b = sr.ReadUntil('e'); - switch (b) - { - case "Tru": - return new Ast.BooleanNode(true); - case "Fals": - return new Ast.BooleanNode(false); - } - + string b = sr.Peek() == 'T' ? sr.Read(4) : sr.Read(5); + if(b == "True" || b == "False") + return new Ast.BooleanNode(b == "True"); throw new ParseException("expected bool, True or False"); } private Ast.NoneNode ParseNone(SeekableStringReader sr) { // None - string n = sr.ReadUntil('e'); - if(n=="Non") + string n = sr.Read(4); + if(n == "None") return Ast.NoneNode.Instance; throw new ParseException("expected None"); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/serpent-1.42/dotnet/Serpent/Razorvine.Serpent/SeekableStringReader.cs new/serpent-1.43/dotnet/Serpent/Razorvine.Serpent/SeekableStringReader.cs --- old/serpent-1.42/dotnet/Serpent/Razorvine.Serpent/SeekableStringReader.cs 2024-03-07 01:16:23.000000000 +0100 +++ new/serpent-1.43/dotnet/Serpent/Razorvine.Serpent/SeekableStringReader.cs 2026-05-30 16:42:25.000000000 +0200 @@ -117,8 +117,13 @@ char c=Read(); if(c=='#') { - ReadUntil('\n'); - return; + try { + ReadUntil('\n'); + } catch (ParseException) { + // terminator not found, this is fine (comment until end of string) + _cursor = _str.Length; + } + continue; } if (char.IsWhiteSpace(c)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/serpent-1.42/dotnet/Serpent/Razorvine.Serpent/Serializer.cs new/serpent-1.43/dotnet/Serpent/Razorvine.Serpent/Serializer.cs --- old/serpent-1.42/dotnet/Serpent/Razorvine.Serpent/Serializer.cs 2025-05-05 22:53:45.000000000 +0200 +++ new/serpent-1.43/dotnet/Serpent/Razorvine.Serpent/Serializer.cs 2026-05-30 16:56:11.000000000 +0200 @@ -524,9 +524,19 @@ protected void Serialize_complex(ComplexNumber cplx, TextWriter tw, int level) { + if(double.IsNaN(cplx.Real) || double.IsNaN(cplx.Imaginary)) + { + tw.Write("{'__class__':'complex','real':"); + Serialize_primitive(cplx.Real, tw, level); + tw.Write(",'imag':"); + Serialize_primitive(cplx.Imaginary, tw, level); + tw.Write("}"); + return; + } + tw.Write("("); Serialize_primitive(cplx.Real, tw, level); - if(cplx.Imaginary>=0) + if(cplx.Imaginary>=0 && BitConverter.DoubleToInt64Bits(cplx.Imaginary) >= 0) tw.Write("+"); Serialize_primitive(cplx.Imaginary, tw, level); tw.Write("j)"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/serpent-1.42/dotnet/Serpent/Tests/ParserTest.cs new/serpent-1.43/dotnet/Serpent/Tests/ParserTest.cs --- old/serpent-1.42/dotnet/Serpent/Tests/ParserTest.cs 2025-04-25 12:23:51.000000000 +0200 +++ new/serpent-1.43/dotnet/Serpent/Tests/ParserTest.cs 2026-05-30 16:57:35.000000000 +0200 @@ -73,6 +73,14 @@ } [Fact] + public void TestNestedComplex() + { + var p = new Parser(); + p.Parse("((1, 2j), 3)"); + p.Parse("(1, (2, 3j))"); + } + + [Fact] public void TestWeirdFloats() { var p = new Parser(); @@ -480,6 +488,11 @@ cplx.Real = -3.2e-32; cplx.Imaginary = -9.9e-44; Assert.Equal(cplx, p.Parse("(-3.2e-32-9.9e-44j)").Root); + + // new cases + cplx.Real = 1.0; + cplx.Imaginary = -0.0; + Assert.Equal(cplx, p.Parse("(1.0-0.0j)").Root); } [Fact] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/serpent-1.42/dotnet/Serpent/Tests/SerializeTest.cs new/serpent-1.43/dotnet/Serpent/Tests/SerializeTest.cs --- old/serpent-1.42/dotnet/Serpent/Tests/SerializeTest.cs 2025-04-25 12:26:42.000000000 +0200 +++ new/serpent-1.43/dotnet/Serpent/Tests/SerializeTest.cs 2026-05-30 16:58:06.000000000 +0200 @@ -191,6 +191,10 @@ ser = serpent.Serialize(cplx); data = strip_header(ser); Assert.Equal(B("(-2-3j)"), data); + cplx = new ComplexNumber(1.0, -0.0); + ser = serpent.Serialize(cplx); + data = strip_header(ser); + Assert.Equal(B("(1-0j)"), data); } [Fact] @@ -199,10 +203,11 @@ var serpent = new Serializer(); var doubles = new object[] {double.PositiveInfinity, double.NegativeInfinity, double.NaN, float.PositiveInfinity, float.NegativeInfinity, float.NaN, - new ComplexNumber(double.PositiveInfinity, 3.4)}; + new ComplexNumber(double.PositiveInfinity, 3.4), + new ComplexNumber(1.0, double.NaN)}; var ser = serpent.Serialize(doubles); var data = strip_header(ser); - Assert.Equal("(1e30000,-1e30000,{'__class__':'float','value':'nan'},1e30000,-1e30000,{'__class__':'float','value':'nan'},(1e30000+3.4j))", S(data)); + Assert.Equal("(1e30000,-1e30000,{'__class__':'float','value':'nan'},1e30000,-1e30000,{'__class__':'float','value':'nan'},(1e30000+3.4j),{'__class__':'complex','real':1,'imag':{'__class__':'float','value':'nan'}})", S(data)); } [Fact] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/serpent-1.42/dotnet/Serpent/Tests/StringreaderTest.cs new/serpent-1.43/dotnet/Serpent/Tests/StringreaderTest.cs --- old/serpent-1.42/dotnet/Serpent/Tests/StringreaderTest.cs 2025-04-25 12:26:42.000000000 +0200 +++ new/serpent-1.43/dotnet/Serpent/Tests/StringreaderTest.cs 2026-05-30 16:31:50.000000000 +0200 @@ -32,6 +32,16 @@ } [Fact] + public void TestSkipMultipleComments() + { + using(var s = new SeekableStringReader("# comment 1\n# comment 2\n# comment 3\n[1,2,3]")) + { + s.SkipWhitespace(); + Assert.Equal('[', s.Peek()); + } + } + + [Fact] public void TestRead() { var s = new SeekableStringReader("hello"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/serpent-1.42/dotnet/Serpent/Tests/Tests.csproj new/serpent-1.43/dotnet/Serpent/Tests/Tests.csproj --- old/serpent-1.42/dotnet/Serpent/Tests/Tests.csproj 2025-04-25 12:31:13.000000000 +0200 +++ new/serpent-1.43/dotnet/Serpent/Tests/Tests.csproj 2026-05-30 16:33:39.000000000 +0200 @@ -1,6 +1,6 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> - <TargetFramework>net9.0</TargetFramework> + <TargetFramework>net10.0</TargetFramework> <IsPackable>false</IsPackable> <LangVersion>latestmajor</LangVersion> <RootNamespace>UnitTests</RootNamespace> @@ -8,9 +8,9 @@ <OutputType>Library</OutputType> </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.0-preview-25107-01" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.0" /> <PackageReference Include="xunit" Version="2.9.3" /> - <PackageReference Include="xunit.runner.visualstudio" Version="3.0.2"> + <PackageReference Include="xunit.runner.visualstudio" Version="3.1.5"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/serpent-1.42/java/.idea/libraries/Maven__org_hamcrest_hamcrest_core_1_3.xml new/serpent-1.43/java/.idea/libraries/Maven__org_hamcrest_hamcrest_core_1_3.xml --- old/serpent-1.42/java/.idea/libraries/Maven__org_hamcrest_hamcrest_core_1_3.xml 2020-10-06 19:31:54.000000000 +0200 +++ new/serpent-1.43/java/.idea/libraries/Maven__org_hamcrest_hamcrest_core_1_3.xml 1970-01-01 01:00:00.000000000 +0100 @@ -1,13 +0,0 @@ -<component name="libraryTable"> - <library name="Maven: org.hamcrest:hamcrest-core:1.3"> - <CLASSES> - <root url="jar://$MAVEN_REPOSITORY$/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar!/" /> - </CLASSES> - <JAVADOC> - <root url="jar://$MAVEN_REPOSITORY$/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-javadoc.jar!/" /> - </JAVADOC> - <SOURCES> - <root url="jar://$MAVEN_REPOSITORY$/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar!/" /> - </SOURCES> - </library> -</component> \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/serpent-1.42/java/mvn-release-readme.txt new/serpent-1.43/java/mvn-release-readme.txt --- old/serpent-1.42/java/mvn-release-readme.txt 2020-10-06 19:31:54.000000000 +0200 +++ new/serpent-1.43/java/mvn-release-readme.txt 2026-05-30 18:07:11.000000000 +0200 @@ -1,14 +1,18 @@ -Making a release to Sonatype Nexus/maven central: +Making a release to Maven Central (Central Publishing Portal): -$ mvn release:clean release:prepare release:perform +First make sure that JAVA_HOME is set (needed for the javadoc tool) +For example: export JAVA_HOME=/usr/lib/jvm/java-21-openjdk/ -Requires version number in the pom.xml to be "x.y-SNAPSHOT". +Ensure your ~/.m2/settings.xml has a <server> entry for 'central' with your User Token. -Finalise and publish the release via https://oss.sonatype.org/#stagingRepositories +$ mvn clean deploy -Prelease + + +Monitor progress and finalise via https://central.sonatype.com See also: -http://java.dzone.com/articles/deploy-maven-central -http://central.sonatype.org/pages/apache-maven.html#performing-a-release-deployment +https://central.sonatype.com +https://central.sonatype.org/publish/publish-portal/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/serpent-1.42/java/pom.xml new/serpent-1.43/java/pom.xml --- old/serpent-1.42/java/pom.xml 2021-05-15 00:01:51.000000000 +0200 +++ new/serpent-1.43/java/pom.xml 2026-05-30 18:10:11.000000000 +0200 @@ -1,15 +1,9 @@ <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> - <parent> - <groupId>org.sonatype.oss</groupId> - <artifactId>oss-parent</artifactId> - <version>9</version> - </parent> - <groupId>net.razorvine</groupId> <artifactId>serpent</artifactId> - <version>1.41-SNAPSHOT</version> + <version>1.43</version> <packaging>jar</packaging> <name>serpent</name> @@ -19,12 +13,74 @@ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <build> + <plugins> + <plugin> + <groupId>org.sonatype.central</groupId> + <artifactId>central-publishing-maven-plugin</artifactId> + <version>0.7.0</version> + <extensions>true</extensions> + <configuration> + <publishingServerId>central</publishingServerId> + <autoPublish>true</autoPublish> + <waitUntil>published</waitUntil> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-source-plugin</artifactId> + <version>3.3.1</version> + <executions> + <execution> + <id>attach-sources</id> + <goals> + <goal>jar-no-fork</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + <version>3.12.0</version> + <configuration> + <doclint>none</doclint> + </configuration> + <executions> + <execution> + <id>attach-javadocs</id> + <goals> + <goal>jar</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + <version>3.5.0</version> + <executions> + <execution> + <id>enforce-maven</id> + <goals> + <goal>enforce</goal> + </goals> + <configuration> + <rules> + <requireMavenVersion> + <version>3.6.3</version> + </requireMavenVersion> + </rules> + </configuration> + </execution> + </executions> + </plugin> + </plugins> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> - <version>3.8.0</version> + <version>3.15.0</version> <configuration> <compilerArgs> <arg>-Xlint:all</arg> @@ -36,19 +92,12 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-gpg-plugin</artifactId> - <version>1.5</version> + <version>3.2.8</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-release-plugin</artifactId> - <version>2.5.2</version> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-javadoc-plugin</artifactId> - <configuration> - <doclint>none</doclint> - </configuration> + <version>3.3.1</version> </plugin> </plugins> </pluginManagement> @@ -57,7 +106,7 @@ <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> - <version>4.13.1</version> + <version>4.13.2</version> <scope>test</scope> </dependency> </dependencies> @@ -69,7 +118,7 @@ <scm> <url>https://github.com/irmen/Serpent</url> <connection>scm:git:https://github.com/irmen/Serpent.git</connection> - <developerConnection>scm:git:https://github.com/irmen/Serpent.git</developerConnection> + <developerConnection>scm:git:[email protected]:irmen/Serpent.git</developerConnection> <tag>HEAD</tag> </scm> <issueManagement> @@ -92,4 +141,27 @@ <url>http://www.opensource.org/licenses/mit-license.php</url> </license> </licenses> + <profiles> + <profile> + <id>release</id> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-gpg-plugin</artifactId> + <version>3.2.8</version> + <executions> + <execution> + <id>sign-artifacts</id> + <phase>verify</phase> + <goals> + <goal>sign</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + </profiles> </project> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/serpent-1.42/java/src/main/java/net/razorvine/serpent/ComplexNumber.java new/serpent-1.43/java/src/main/java/net/razorvine/serpent/ComplexNumber.java --- old/serpent-1.42/java/src/main/java/net/razorvine/serpent/ComplexNumber.java 2020-10-06 19:31:54.000000000 +0200 +++ new/serpent-1.43/java/src/main/java/net/razorvine/serpent/ComplexNumber.java 2026-05-30 16:52:37.000000000 +0200 @@ -29,7 +29,7 @@ { StringBuilder sb=new StringBuilder(); sb.append(real); - if(imaginary>0) + if(imaginary>=0 && Math.copySign(1.0, imaginary) > 0) sb.append('+'); return sb.append(imaginary).append('i').toString(); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/serpent-1.42/java/src/main/java/net/razorvine/serpent/Parser.java new/serpent-1.43/java/src/main/java/net/razorvine/serpent/Parser.java --- old/serpent-1.42/java/src/main/java/net/razorvine/serpent/Parser.java 2021-05-10 22:30:25.000000000 +0200 +++ new/serpent-1.43/java/src/main/java/net/razorvine/serpent/Parser.java 2026-05-30 16:40:53.000000000 +0200 @@ -107,9 +107,15 @@ // if the last character before the closing parenthesis is a 'j', it is a complex number { int bm = sr.bookmark(); - String betweenparens = sr.readUntil(")\n").trim(); + String betweenparens = sr.readUntil(")\n"); sr.flipBack(bm); - return betweenparens.endsWith("j") ? parseComplex(sr) : parseTuple(sr); + String trimmed = betweenparens.trim(); + if(trimmed.endsWith("j") && trimmed.indexOf(',')<0 && (trimmed.indexOf('(')<0 || trimmed.lastIndexOf('(')==0)) + { + // complex number + return parseComplex(sr); + } + return parseTuple(sr); } default: throw new ParseException("invalid sequencetype char"); @@ -644,19 +650,17 @@ PrimitiveNode<Boolean> parseBool(SeekableStringReader sr) { // True,False - String b = sr.readUntil('e'); - if(b.equals("Tru")) - return new BooleanNode(true); - if(b.equals("Fals")) - return new BooleanNode(false); + String b = sr.peek()=='T'? sr.read(4) : sr.read(5); + if(b.equals("True") || b.equals("False")) + return new BooleanNode(b.equals("True")); throw new ParseException("expected bool, True or False"); } NoneNode parseNone(SeekableStringReader sr) { // None - String n = sr.readUntil('e'); - if(n.equals("Non")) + String n = sr.read(4); + if(n.equals("None")) return NoneNode.Instance; throw new ParseException("expected None"); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/serpent-1.42/java/src/main/java/net/razorvine/serpent/SeekableStringReader.java new/serpent-1.43/java/src/main/java/net/razorvine/serpent/SeekableStringReader.java --- old/serpent-1.42/java/src/main/java/net/razorvine/serpent/SeekableStringReader.java 2020-10-06 19:31:54.000000000 +0200 +++ new/serpent-1.43/java/src/main/java/net/razorvine/serpent/SeekableStringReader.java 2026-05-30 16:36:06.000000000 +0200 @@ -149,8 +149,13 @@ char c=read(); if(c=='#') { - readUntil('\n'); - return; + try { + readUntil('\n'); + } catch (ParseException x) { + // terminator not found, this is fine (comment until end of string) + cursor = str.length(); + } + continue; } if(!Character.isWhitespace(c)) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/serpent-1.42/java/src/main/java/net/razorvine/serpent/Serializer.java new/serpent-1.43/java/src/main/java/net/razorvine/serpent/Serializer.java --- old/serpent-1.42/java/src/main/java/net/razorvine/serpent/Serializer.java 2021-05-10 22:02:49.000000000 +0200 +++ new/serpent-1.43/java/src/main/java/net/razorvine/serpent/Serializer.java 2026-05-30 16:53:38.000000000 +0200 @@ -504,9 +504,19 @@ protected void serialize_complex(ComplexNumber cplx, StringWriter sw, int level) { + if(Double.isNaN(cplx.real) || Double.isNaN(cplx.imaginary)) + { + sw.write("{'__class__':'complex','real':"); + serialize_primitive(cplx.real, sw, level); + sw.write(",'imag':"); + serialize_primitive(cplx.imaginary, sw, level); + sw.write("}"); + return; + } + sw.write("("); serialize_primitive(cplx.real, sw, level); - if(cplx.imaginary>=0) + if(cplx.imaginary>=0 && Math.copySign(1.0, cplx.imaginary) > 0) sw.write("+"); serialize_primitive(cplx.imaginary, sw, level); sw.write("j)"); @@ -588,7 +598,7 @@ } protected IClassSerializer getCustomConverter(Class<?> type) { - IClassSerializer converter = classToDictRegistry.get(type.getClass()); + IClassSerializer converter = classToDictRegistry.get(type); if(converter!=null) { return converter; // exact match } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/serpent-1.42/java/src/test/java/net/razorvine/serpent/test/ParserTest.java new/serpent-1.43/java/src/test/java/net/razorvine/serpent/test/ParserTest.java --- old/serpent-1.42/java/src/test/java/net/razorvine/serpent/test/ParserTest.java 2020-10-06 19:31:54.000000000 +0200 +++ new/serpent-1.43/java/src/test/java/net/razorvine/serpent/test/ParserTest.java 2026-05-30 16:57:03.000000000 +0200 @@ -102,6 +102,14 @@ } @Test + public void TestNestedComplex() + { + Parser p = new Parser(); + p.parse("((1, 2j), 3)"); + p.parse("(1, (2, 3j))"); + } + + @Test public void TestWeirdFloats() { Parser p = new Parser(); @@ -478,6 +486,11 @@ cplx.real = -3.2e-32; cplx.imaginary = -9.9e-44; assertEquals(cplx, p.parse("(-3.2e-32-9.9e-44j)").root); + + // new cases + cplx.real = 1.0; + cplx.imaginary = -0.0; + assertEquals(cplx, p.parse("(1.0-0.0j)").root); } @Test diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/serpent-1.42/java/src/test/java/net/razorvine/serpent/test/SerializeTest.java new/serpent-1.43/java/src/test/java/net/razorvine/serpent/test/SerializeTest.java --- old/serpent-1.42/java/src/test/java/net/razorvine/serpent/test/SerializeTest.java 2021-05-10 22:43:58.000000000 +0200 +++ new/serpent-1.43/java/src/test/java/net/razorvine/serpent/test/SerializeTest.java 2026-05-30 16:57:30.000000000 +0200 @@ -81,6 +81,38 @@ @Test + public void testCustomConverter() + { + class MyClass implements Serializable { + public String name = "test"; + } + + class MyConverter implements IClassSerializer { + public Map<String, Object> convert(Object obj) { + Map<String, Object> result = new HashMap<>(); + result.put("__class__", "ConvertedMyClass"); + return result; + } + } + + class ObjectConverter implements IClassSerializer { + public Map<String, Object> convert(Object obj) { + Map<String, Object> result = new HashMap<>(); + result.put("__class__", "ConvertedObject"); + return result; + } + } + + Serializer.registerClass(MyClass.class, new MyConverter()); + + Serializer ser = new Serializer(); + byte[] data = ser.serialize(new MyClass()); + String result = S(data); + + assertTrue(result.contains("ConvertedMyClass")); + } + + @Test public void testException() { Serializer.registerClass(IllegalArgumentException.class, null); @@ -404,6 +436,10 @@ ser = serpent.serialize(cplx); data = strip_header(ser); assertEquals("(-2.5-3.9j)", S(data)); + cplx = new ComplexNumber(1.0, -0.0); + ser = serpent.serialize(cplx); + data = strip_header(ser); + assertEquals("(1.0-0.0j)", S(data)); } @Test @@ -412,10 +448,11 @@ Serializer serpent = new Serializer(); Object[] doubles = new Object[] {Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NaN, Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NaN, - new ComplexNumber(Double.POSITIVE_INFINITY, 3.3)}; + new ComplexNumber(Double.POSITIVE_INFINITY, 3.3), + new ComplexNumber(1.0, Double.NaN)}; byte[] ser = serpent.serialize(doubles); byte[] data = strip_header(ser); - assertEquals("(1e30000,-1e30000,{'__class__':'float','value':'nan'},1e30000,-1e30000,{'__class__':'float','value':'nan'},(1e30000+3.3j))", S(data)); + assertEquals("(1e30000,-1e30000,{'__class__':'float','value':'nan'},1e30000,-1e30000,{'__class__':'float','value':'nan'},(1e30000+3.3j),{'__class__':'complex','real':1.0,'imag':{'__class__':'float','value':'nan'}})", S(data)); } @Test diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/serpent-1.42/java/src/test/java/net/razorvine/serpent/test/StringreaderTest.java new/serpent-1.43/java/src/test/java/net/razorvine/serpent/test/StringreaderTest.java --- old/serpent-1.42/java/src/test/java/net/razorvine/serpent/test/StringreaderTest.java 2020-10-06 19:31:54.000000000 +0200 +++ new/serpent-1.43/java/src/test/java/net/razorvine/serpent/test/StringreaderTest.java 2026-05-30 16:31:42.000000000 +0200 @@ -46,6 +46,14 @@ } @Test + public void testSkipMultipleComments() + { + SeekableStringReader s = new SeekableStringReader("# comment 1\n# comment 2\n# comment 3\n[1,2,3]"); + s.skipWhitespace(); + assertEquals('[', s.peek()); + } + + @Test public void testRanges() { SeekableStringReader s = new SeekableStringReader("hello"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/serpent-1.42/serpent.egg-info/PKG-INFO new/serpent-1.43/serpent.egg-info/PKG-INFO --- old/serpent-1.42/serpent.egg-info/PKG-INFO 2025-10-26 22:58:11.000000000 +0100 +++ new/serpent-1.43/serpent.egg-info/PKG-INFO 2026-05-30 18:30:10.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: serpent -Version: 1.42 +Version: 1.43 Summary: Serialization based on ast.literal_eval Home-page: https://github.com/irmen/Serpent Author: Irmen de Jong diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/serpent-1.42/serpent.egg-info/SOURCES.txt new/serpent-1.43/serpent.egg-info/SOURCES.txt --- old/serpent-1.42/serpent.egg-info/SOURCES.txt 2025-10-26 22:58:11.000000000 +0100 +++ new/serpent-1.43/serpent.egg-info/SOURCES.txt 2026-05-30 18:30:10.000000000 +0200 @@ -35,7 +35,6 @@ java/mvn-release-readme.txt java/pom.xml java/serpent.iml -java/.idea/libraries/Maven__org_hamcrest_hamcrest_core_1_3.xml java/src/main/java/net/razorvine/serpent/ComplexNumber.java java/src/main/java/net/razorvine/serpent/DebugVisitor.java java/src/main/java/net/razorvine/serpent/IClassSerializer.java diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/serpent-1.42/serpent.py new/serpent-1.43/serpent.py --- old/serpent-1.42/serpent.py 2025-10-26 22:57:18.000000000 +0100 +++ new/serpent-1.43/serpent.py 2026-05-30 17:06:34.000000000 +0200 @@ -55,7 +55,7 @@ import enum from collections.abc import KeysView, ValuesView, ItemsView -__version__ = "1.42" +__version__ = "1.43" __all__ = ["dump", "dumps", "load", "loads", "register_class", "unregister_class", "tobytes"] @@ -99,11 +99,17 @@ def _ser_OrderedDict(obj, serializer, outputstream, indentlevel): - obj = { - "__class__": "collections.OrderedDict" if serializer.module_in_classname else "OrderedDict", - "items": list(obj.items()) - } - serializer._serialize(obj, outputstream, indentlevel) + if id(obj) in serializer.serialized_obj_ids: + raise ValueError("Circular reference detected (OrderedDict)") + serializer.serialized_obj_ids.add(id(obj)) + try: + obj = { + "__class__": "collections.OrderedDict" if serializer.module_in_classname else "OrderedDict", + "items": list(obj.items()) + } + serializer._serialize(obj, outputstream, indentlevel) + finally: + serializer.serialized_obj_ids.discard(id(obj)) def _ser_DictView(obj, serializer, outputstream, indentlevel): @@ -289,9 +295,16 @@ dispatch[float] = ser_builtins_float def ser_builtins_complex(self, complex_obj, out, level): + if math.isnan(complex_obj.real) or math.isnan(complex_obj.imag): + out.append("{'__class__':'complex','real':") + self.ser_builtins_float(complex_obj.real, out, level) + out.append(",'imag':") + self.ser_builtins_float(complex_obj.imag, out, level) + out.append("}") + return out.append("(") self.ser_builtins_float(complex_obj.real, out, level) - if complex_obj.imag >= 0: + if complex_obj.imag >= 0 and math.copysign(1.0, complex_obj.imag) > 0: out.append("+") self.ser_builtins_float(complex_obj.imag, out, level) out.append("j)") @@ -499,6 +512,9 @@ if has_own_getstate: value = obj.__getstate__() if isinstance(value, dict): + if "__class__" not in value: + value = value.copy() + value["__class__"] = self.get_class_name(obj) self.ser_builtins_dict(value, out, level) return else: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/serpent-1.42/tests/test_serpent.py new/serpent-1.43/tests/test_serpent.py --- old/serpent-1.42/tests/test_serpent.py 2022-06-26 15:30:37.000000000 +0200 +++ new/serpent-1.43/tests/test_serpent.py 2026-05-30 16:56:43.000000000 +0200 @@ -299,6 +299,12 @@ ser = serpent.dumps(2 - 3j) data = strip_header(ser) self.assertEqual(b"(2.0-3.0j)", data) + ser = serpent.dumps(complex(1.0, -0.0)) + data = strip_header(ser) + self.assertEqual(b"(1.0-0.0j)", data) + ser = serpent.dumps(complex(float('nan'), 1.0)) + data = strip_header(ser) + self.assertIn(b"'__class__':'complex'", data) def test_bool(self): ser = serpent.dumps(True) @@ -495,7 +501,18 @@ c = Class2() ser = serpent.dumps(c) data = serpent.loads(ser) - self.assertEqual({'attr': 42}, data) + self.assertEqual({'__class__': 'Class2', 'attr': 42}, data) + + def test_class_getstate_dict(self): + class MyObj: + def __init__(self, val): + self.val = val + def __getstate__(self): + return {"val": self.val} + obj = MyObj(42) + ser = serpent.dumps(obj).decode('utf-8') + self.assertIn("'__class__':'MyObj'", ser) + self.assertIn("'val':42", ser) def test_class_slots(self): c = SlotsClass() @@ -972,6 +989,13 @@ serpent.dumps(d) self.assertEqual("Circular reference detected (class)", str(e.exception)) + def testOrderedDictCycle(self): + od = collections.OrderedDict() + od['self'] = od + with self.assertRaises(ValueError) as e: + serpent.dumps(od) + self.assertEqual("Circular reference detected (OrderedDict)", str(e.exception)) + # noinspection PyUnreachableCode def testMaxLevel(self): ser = serpent.Serializer()
