Skip to content

Commit b16859d

Browse files
Add a Python module for log version parsing (#10107)
1 parent ddb37d3 commit b16859d

12 files changed

Lines changed: 617 additions & 2 deletions

File tree

.gitignore

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ FodyWeavers.xsd
382382
!.vscode/tasks.json
383383
!.vscode/launch.json
384384
!.vscode/extensions.json
385-
*.code-workspace
385+
!.vscode/*.code-snippets
386386

387387
# Local History for Visual Studio Code
388388
.history/
@@ -397,6 +397,10 @@ FodyWeavers.xsd
397397
# JetBrains Rider
398398
*.sln.iml
399399

400+
# macOS
401+
.DS_Store
402+
403+
400404
#######################
401405
# Repository specific #
402406
#######################
@@ -411,7 +415,7 @@ tests/functionaltests.*.xml
411415
*.g.txt
412416

413417
# The applicationhost.config is ignored, but already comitted on purpose
414-
# Reason: The localtest.me setting needs to be configured in the <sites>-section.
418+
# Reason: The localtest.me setting needs to be configured in the <sites>-section.
415419
# See ReadMe.md for more information
416420
.vs/config/applicationhost.config
417421

@@ -427,3 +431,5 @@ src/NuGetGallery/App_Data/Files/*
427431
!src/NuGetGallery/App_Data/Files/Content/
428432
!src/NuGetGallery/Views/Packages/
429433
!src/NuGetGallery/Branding/Views/Packages/
434+
435+

python/.gitignore

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
##### Python ignores from https://raw.githubusercontent.com/github/gitignore/main/Python.gitignore
2+
3+
# Byte-compiled / optimized / DLL files
4+
__pycache__/
5+
*.py[cod]
6+
*$py.class
7+
8+
# C extensions
9+
*.so
10+
11+
# Distribution / packaging
12+
.Python
13+
build/
14+
develop-eggs/
15+
dist/
16+
downloads/
17+
eggs/
18+
.eggs/
19+
lib/
20+
lib64/
21+
parts/
22+
sdist/
23+
var/
24+
wheels/
25+
share/python-wheels/
26+
*.egg-info/
27+
.installed.cfg
28+
*.egg
29+
MANIFEST
30+
31+
# PyInstaller
32+
# Usually these files are written by a python script from a template
33+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
34+
*.manifest
35+
*.spec
36+
37+
# Installer logs
38+
pip-log.txt
39+
pip-delete-this-directory.txt
40+
41+
# Unit test / coverage reports
42+
htmlcov/
43+
.tox/
44+
.nox/
45+
.coverage
46+
.coverage.*
47+
.cache
48+
nosetests.xml
49+
coverage.xml
50+
*.cover
51+
*.py,cover
52+
.hypothesis/
53+
.pytest_cache/
54+
cover/
55+
56+
# Translations
57+
*.mo
58+
*.pot
59+
60+
# Django stuff:
61+
*.log
62+
local_settings.py
63+
db.sqlite3
64+
db.sqlite3-journal
65+
66+
# Flask stuff:
67+
instance/
68+
.webassets-cache
69+
70+
# Scrapy stuff:
71+
.scrapy
72+
73+
# Sphinx documentation
74+
docs/_build/
75+
76+
# PyBuilder
77+
.pybuilder/
78+
target/
79+
80+
# Jupyter Notebook
81+
.ipynb_checkpoints
82+
83+
# IPython
84+
profile_default/
85+
ipython_config.py
86+
87+
# pyenv
88+
# For a library or package, you might want to ignore these files since the code is
89+
# intended to run in multiple environments; otherwise, check them in:
90+
# .python-version
91+
92+
# pipenv
93+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
94+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
95+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
96+
# install all needed dependencies.
97+
#Pipfile.lock
98+
99+
# poetry
100+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
101+
# This is especially recommended for binary packages to ensure reproducibility, and is more
102+
# commonly ignored for libraries.
103+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
104+
#poetry.lock
105+
106+
# pdm
107+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
108+
#pdm.lock
109+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
110+
# in version control.
111+
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
112+
.pdm.toml
113+
.pdm-python
114+
.pdm-build/
115+
116+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
117+
__pypackages__/
118+
119+
# Celery stuff
120+
celerybeat-schedule
121+
celerybeat.pid
122+
123+
# SageMath parsed files
124+
*.sage.py
125+
126+
# Environments
127+
.env
128+
.venv
129+
env/
130+
venv/
131+
ENV/
132+
env.bak/
133+
venv.bak/
134+
135+
# Spyder project settings
136+
.spyderproject
137+
.spyproject
138+
139+
# Rope project settings
140+
.ropeproject
141+
142+
# mkdocs documentation
143+
/site
144+
145+
# mypy
146+
.mypy_cache/
147+
.dmypy.json
148+
dmypy.json
149+
150+
# Pyre type checker
151+
.pyre/
152+
153+
# pytype static type analyzer
154+
.pytype/
155+
156+
# Cython debug symbols
157+
cython_debug/

python/StatsLogParser.slnx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<Solution>
2+
<Properties Name="Visual Studio">
3+
<Property Name="OpenWith" Value="Visual Studio Version 17" />
4+
</Properties>
5+
<Folder Name="/Solution Items/">
6+
<File Path=".editorconfig" />
7+
</Folder>
8+
<Folder Name="/Legacy Projects/">
9+
<Project Path="src\NuGet.Jobs.Common\NuGet.Jobs.Common.csproj" Type="C#" />
10+
<Project Path="src\Stats.AzureCdnLogs.Common\Stats.AzureCdnLogs.Common.csproj" Type="C#" />
11+
<Project Path="src\Stats.ImportAzureCdnStatistics\Stats.ImportAzureCdnStatistics.csproj" Type="C#" />
12+
<Project Path="src\Stats.LogInterpretation\Stats.LogInterpretation.csproj" Type="C#" />
13+
<Project Path="tests\Tests.Stats.ImportAzureCdnStatistics\Tests.Stats.ImportAzureCdnStatistics.csproj" Type="C#" />
14+
</Folder>
15+
<Project Path="src\StatsLogParser\StatsLogParser.pyproj" Type="888888a0-9f3d-457c-b088-3a5042f75d52">
16+
<Build Project="false" />
17+
</Project>
18+
</Solution>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"files.autoSave": "onFocusChange",
3+
"python.testing.unittestArgs": [
4+
"-v",
5+
"-s",
6+
"./tests",
7+
"-p",
8+
"test_*.py"
9+
],
10+
"python.testing.pytestEnabled": true,
11+
"python.testing.autoTestDiscoverOnSaveEnabled": true
12+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
2+
<PropertyGroup>
3+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
4+
<SchemaVersion>2.0</SchemaVersion>
5+
<ProjectGuid>6defb0fc-4057-4f1b-81b4-6df4f75a1233</ProjectGuid>
6+
<ProjectHome>.</ProjectHome>
7+
<StartupFile>
8+
</StartupFile>
9+
<SearchPath>
10+
</SearchPath>
11+
<WorkingDirectory>.</WorkingDirectory>
12+
<OutputPath>.</OutputPath>
13+
<Name>StatsLogParser</Name>
14+
<RootNamespace>StatsLogParser</RootNamespace>
15+
<InterpreterId>MSBuild|.venv|$(MSBuildProjectFullPath)</InterpreterId>
16+
<TestFramework>pytest</TestFramework>
17+
<UnitTestPattern>test*.py</UnitTestPattern>
18+
<UnitTestRootDirectory>.</UnitTestRootDirectory>
19+
</PropertyGroup>
20+
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
21+
<DebugSymbols>true</DebugSymbols>
22+
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
23+
</PropertyGroup>
24+
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
25+
<DebugSymbols>true</DebugSymbols>
26+
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
27+
</PropertyGroup>
28+
<ItemGroup>
29+
<Compile Include="loginterpretation\nugetversion.py" />
30+
<Compile Include="loginterpretation\packagedefinition.py">
31+
<SubType>Code</SubType>
32+
</Compile>
33+
<Compile Include="loginterpretation\semanticversion.py" />
34+
<Compile Include="loginterpretation\__init__.py">
35+
<SubType>Code</SubType>
36+
</Compile>
37+
<Compile Include="tests\test_packagedefinition.py" />
38+
<Compile Include="tests\__init__.py">
39+
<SubType>Code</SubType>
40+
</Compile>
41+
</ItemGroup>
42+
<ItemGroup>
43+
<Interpreter Include=".venv\">
44+
<Id>.venv</Id>
45+
<Version>3.9</Version>
46+
<Description>.venv (Python 3.9 (64-bit))</Description>
47+
<InterpreterPath>Scripts\python.exe</InterpreterPath>
48+
<WindowsInterpreterPath>Scripts\pythonw.exe</WindowsInterpreterPath>
49+
<PathEnvironmentVariable>PYTHONPATH</PathEnvironmentVariable>
50+
<Architecture>X64</Architecture>
51+
</Interpreter>
52+
</ItemGroup>
53+
<ItemGroup>
54+
<Content Include="requirements.txt" />
55+
</ItemGroup>
56+
<ItemGroup>
57+
<Folder Include="loginterpretation\" />
58+
<Folder Include="tests\" />
59+
</ItemGroup>
60+
<ItemGroup>
61+
<InterpreterReference Include="Global|PythonCore|3.9" />
62+
</ItemGroup>
63+
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.targets" />
64+
<!-- Uncomment the CoreCompile target to enable the Build command in
65+
Visual Studio and specify your pre- and post-build commands in
66+
the BeforeBuild and AfterBuild targets below. -->
67+
<!--<Target Name="CoreCompile" />-->
68+
<Target Name="BeforeBuild">
69+
</Target>
70+
<Target Name="AfterBuild">
71+
</Target>
72+
</Project>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"""
2+
Log interpretation package
3+
"""
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
from __future__ import annotations
2+
from dataclasses import dataclass
3+
from typing import List, Optional, Tuple
4+
from .semanticversion import SemanticVersion, Version
5+
6+
@dataclass
7+
class NuGetVersion(SemanticVersion):
8+
9+
@classmethod
10+
def parse(cls, value: str) -> NuGetVersion:
11+
try:
12+
version_string, release_labels, build_metadata = cls.parse_sections(value)
13+
major, minor, patch, revision = cls.parse_version(version_string)
14+
return cls(major, minor, patch, revision, release_labels, build_metadata)
15+
except Exception as e:
16+
raise ValueError(f"Invalid NuGetVersion string: {value}") from e
17+
18+
@classmethod
19+
def try_parse(cls, value: str) -> Optional[NuGetVersion]:
20+
try:
21+
return cls.parse(value)
22+
except ValueError:
23+
return None
24+
25+
@staticmethod
26+
def parse_version(version_string: str) -> Version:
27+
parts = version_string.split(".")
28+
if len(parts) == 3:
29+
return int(parts[0]), int(parts[1]), int(parts[2]), 0
30+
elif len(parts) == 4:
31+
return int(parts[0]), int(parts[1]), int(parts[2]), int(parts[3])
32+
else:
33+
raise ValueError(f"Invalid version string: {version_string}")
34+
35+
@staticmethod
36+
def is_letter_or_digit_or_dash(c: str) -> bool:
37+
return c.isalnum() or c == '-'
38+
39+
@staticmethod
40+
def is_digit(c: str) -> bool:
41+
return c.isdigit()
42+
43+
@staticmethod
44+
def is_valid(s: str, allow_leading_zeros: bool) -> bool:
45+
if not allow_leading_zeros and s.startswith("0") and len(s) > 1:
46+
return False
47+
return all(NuGetVersion.is_letter_or_digit_or_dash(c) for c in s)
48+
49+
@staticmethod
50+
def is_valid_part(s: str, allow_leading_zeros: bool) -> bool:
51+
return NuGetVersion.is_valid(s, allow_leading_zeros)
52+
53+
@staticmethod
54+
def normalize_version_value(version: Version) -> Version:
55+
return version

0 commit comments

Comments
 (0)