Compare commits

..

No commits in common. 'main' and 'wangjing' have entirely different histories.

@ -1,219 +1,2 @@
# OpenRank 算法改进项目
# openrank
这是一个基于 open-digger 和 openrank-neo4j-gds 项目的 OpenRank 算法实现,用于开发者贡献度量和开源社区分析。
## 项目架构
本项目采用模块化架构设计,主要包括以下几个核心部分:
1. **算法核心** (`src/src/algorithm/`):实现了 OpenRank 算法的核心逻辑,包括图构建、迭代计算和结果生成
2. **数据层** (`src/src/data/`):提供数据加载和管理功能,支持模拟数据和真实数据
3. **配置系统** (`src/src/config/`):管理算法参数和环境配置
4. **API 接口** (`src/src/api/`):提供统一的访问接口和查询功能
5. **工具函数** (`src/src/utils/`):通用工具和辅助函数
## 安装
```bash
# 克隆项目
git clone <repository-url>
cd openrank
# 安装依赖
npm install
# 构建项目
npm run build
```
## 快速开始
### 基础使用
```typescript
import { OpenRank } from './src';
// 创建 OpenRank 实例
const openrank = new OpenRank('./data');
// 运行 OpenRank 计算
const startDate = new Date('2024-01-01');
const endDate = new Date('2024-12-31');
const results = await openrank.calculate(startDate, endDate);
// 获取 Top 10 仓库 OpenRank
const topRepos = await openrank.getRepoOpenrank({
startYear: 2024,
startMonth: 1,
endYear: 2024,
endMonth: 12,
limit: 10,
order: 'DESC'
});
console.log('Top 10 仓库:', topRepos);
```
### 高级查询
```typescript
import { MetricsCalculator, MockDataSource } from './src';
const dataSource = new MockDataSource('./data');
const calculator = new MetricsCalculator(dataSource);
// 获取分布统计
const distribution = await calculator.getOpenrankDistribution({
startYear: 2024,
startMonth: 1,
endYear: 2024,
endMonth: 12,
});
// 比较不同时期
const comparison = await calculator.compareOpenrank(
{ startYear: 2024, startMonth: 1, endYear: 2024, endMonth: 6 },
{ startYear: 2024, startMonth: 7, endYear: 2024, endMonth: 12 },
'repo'
);
```
## 配置
### 配置文件
`config/openrank.yml` 中配置算法参数:
```yaml
global:
developerRetentionFactor: 0.5 # 开发者继承比例
repositoryRetentionFactor: 0.3 # 仓库继承比例
attenuationFactor: 0.85 # OpenRank 衰减系数
tolerance: 0.01 # 收敛容差
maxIterations: 100 # 最大迭代次数
activityWeights:
issueComment: 0.5252 # Issue 评论权重
openIssue: 2.2235 # 创建 Issue 权重
openPull: 4.0679 # 创建 PR 权重
reviewComment: 0.7427 # 代码评审权重
mergedPull: 2.0339 # 合入 PR 权重
projectActivityWeights:
# 活动类型权重(项目级 OpenRank 用)
open: 2.0
comment: 0.5
review: 1.0
close: 0.3
commit: 1.5
# 反刷与密度抑制(推荐开启):
antiGaming:
enabled: true
commentTransform: sqrt # 对高频评论做亚线性变换,降低刷量影响
commitTransform: sqrt
linearThresholds: # 前 N 条线性累加超过部分按变换sqrt/log
comment: 3
reviewComment: 3
commit: 1
perItemCap: # 每个 Issue/PR 的单项计数上限,防极端
comment: 50
reviewComment: 40
commit: 20
```
### 环境变量
```bash
# 设置全局收敛容差
export OPENRANK_GLOBAL_TOLERANCE=0.01
# 设置最大迭代次数
export OPENRANK_GLOBAL_MAX_ITERATIONS=100
```
## 算法原理
### 全域 OpenRank
全域 OpenRank 基于全局协作网络计算,考虑以下因素:
1. **网络构建**:以开发者和仓库为节点,活动关系为边
2. **权重计算**:使用活动度指标作为边权重
3. **历史继承**:节点部分继承上个月的 OpenRank 值
4. **迭代收敛**:使用改进的 PageRank 算法计算
### 项目级 OpenRank
项目级 OpenRank 在项目内部计算,包含更多节点类型:
1. **节点类型**开发者、仓库、Issue、Pull Request
2. **复杂网络**:多种关系类型和权重配置
3. **精细参数**:不同节点类型的不同继承因子
## 运行示例
```bash
# 运行基础示例
npm run dev
# 运行测试
npm test
# 检查代码质量
npm run lint
```
## A/B 评估:仓库事件影响
为评估是否引入仓库层事件Star/Fork/Release 等)对项目级 OpenRank 的影响,本项目提供了 A/B 对比脚本:
- 脚本:`scripts/ab_evaluate_repo_events.ts`
- 运行方式:`npm run ab:repo-events`
- 环境变量(可选):
- `GITHUB_TOKEN`GitHub 访问令牌,避免触发未认证的频率限制
- `OR_AB_OWNER`/`OR_AB_REPO`:目标仓库,默认 `FISCO-BCOS/FISCO-BCOS`
## 项目结构
```
openrank/
├── doc/ # 项目文档和规格说明书
├── front/ # 前端子系统
├── model/ # 设计模型和图表
├── src/ # 源代码目录
│ ├── config/ # 配置文件
│ ├── data/ # 数据存储
│ ├── scripts/ # 辅助脚本
│ ├── src/ # 核心源代码
│ ├── test/ # 测试文件
│ └── test_data/ # 测试数据
└── 文献/ # 参考论文和资料
```
## 开发指南
### 添加新的数据源
1. 实现 `DataSource` 接口
2. 在 `src/src/data/` 目录下创建新的数据源类
3. 更新导出文件
### 自定义算法参数
1. 修改 `config/openrank.yml` 配置文件
2. 或使用环境变量覆盖特定参数
3. 或在代码中动态设置配置
## 测试
```bash
# 运行单元测试
npm test
# 运行覆盖率测试
npm run test:coverage
# 运行集成测试
npm run test:integration
```

Binary file not shown.

@ -23,268 +23,10 @@ class OpenRankDashboard {
this.updateLastUpdateTime();
this.setupTabNavigation();
this.setupModeSwitch();
this.setupCodeReviewPage();
// 默认显示开发者分析数据
this.displayDeveloperAnalysis(this.mockData.developers);
this.hydrateFromURL();
}
// 设置代码测评页面功能
setupCodeReviewPage() {
// 运行Pylint测评按钮
document.getElementById('run-lint-btn')?.addEventListener('click', () => {
this.runCodeLinting();
});
// 清空代码按钮
document.getElementById('clear-code-btn')?.addEventListener('click', () => {
const codeInput = document.getElementById('python-code-input');
if (codeInput) {
codeInput.value = '';
this.resetCodeReviewResults();
}
});
// 加载示例按钮
document.getElementById('load-example-btn')?.addEventListener('click', () => {
this.loadExampleCode();
});
}
// 加载示例代码
loadExampleCode() {
const exampleCode = `def calculate_average(numbers):
"""计算数字列表的平均值"""
if not numbers:
return 0
total = sum(numbers)
return total / len(numbers)
def get_user_name():
name = input("请输入您的名字: ")
print(f"你好, {name}!")
return name
# 主程序
if __name__ == "__main__":
user = get_user_name()
scores = [85, 90, 78, 92, 88]
avg = calculate_average(scores)
print(f"平均分数是: {avg}")`;
const codeInput = document.getElementById('python-code-input');
if (codeInput) {
codeInput.value = exampleCode;
this.resetCodeReviewResults();
}
}
// 重置代码测评结果
resetCodeReviewResults() {
document.getElementById('code-score').textContent = '0';
document.getElementById('score-quality').textContent = '待评分';
document.getElementById('score-quality').className = 'score-quality';
document.getElementById('issues-count').textContent = '0';
document.getElementById('issues-list').innerHTML = '<p class="empty-message">请运行测评查看代码中的问题</p>';
document.getElementById('lint-summary').innerHTML = '<p class="empty-message">请运行测评查看代码质量总结</p>';
}
// 运行代码测评
runCodeLinting() {
const codeInput = document.getElementById('python-code-input');
if (!codeInput || !codeInput.value.trim()) {
this.showNotification('请先输入Python代码', 'error');
return;
}
// 模拟Pylint测评过程
this.simulatePylintAnalysis(codeInput.value);
}
// 模拟Pylint分析由于浏览器限制使用模拟数据
simulatePylintAnalysis(code) {
// 这里使用模拟数据实际项目中应该调用后端API
const codeLines = code.split('\n');
// 根据代码内容生成模拟的Pylint问题
const issues = [];
// 检查是否有未使用的导入(模拟)
if (code.includes('import') && !code.includes('from ')) {
issues.push({
type: 'info',
message: '导入了模块但未使用',
line: 1
});
}
// 检查是否有函数缺少文档字符串(模拟)
let inFunction = false;
let functionStartLine = 0;
codeLines.forEach((line, index) => {
if (line.trim().startsWith('def ')) {
inFunction = true;
functionStartLine = index + 1;
} else if (inFunction && line.trim().startsWith('#') || line.trim().startsWith('"""')) {
inFunction = false;
} else if (inFunction && line.trim() && !line.trim().startsWith(' ') && !line.trim().startsWith('#')) {
issues.push({
type: 'warning',
message: '缺少函数文档字符串',
line: functionStartLine
});
inFunction = false;
}
});
// 检查行长度(模拟)
codeLines.forEach((line, index) => {
if (line.length > 79) {
issues.push({
type: 'warning',
message: '行长度超过79个字符',
line: index + 1
});
}
});
// 检查是否有print语句模拟
codeLines.forEach((line, index) => {
if (line.includes('print(') && !line.includes('"""') && !line.includes("''")) {
issues.push({
type: 'info',
message: '考虑使用logging模块替代print语句',
line: index + 1
});
}
});
// 检查是否有input语句模拟
codeLines.forEach((line, index) => {
if (line.includes('input(')) {
issues.push({
type: 'warning',
message: '生产环境中应避免使用input()函数',
line: index + 1
});
}
});
// 生成随机的额外问题(增加模拟真实性)
const randomIssues = [
{ type: 'info', message: '考虑添加类型提示以提高代码可读性', line: Math.floor(Math.random() * codeLines.length) + 1 },
{ type: 'warning', message: '变量名可以更具描述性', line: Math.floor(Math.random() * codeLines.length) + 1 },
{ type: 'info', message: '考虑添加单元测试', line: 1 }
];
// 随机添加1-2个额外问题
const additionalIssues = Math.floor(Math.random() * 2) + 1;
for (let i = 0; i < additionalIssues; i++) {
issues.push(randomIssues[i]);
}
// 计算分数(基于问题数量和严重性)
let score = 10;
issues.forEach(issue => {
if (issue.type === 'error') score -= 3;
else if (issue.type === 'warning') score -= 1;
else if (issue.type === 'info') score -= 0.5;
});
score = Math.max(0, Math.min(10, score));
score = Math.round(score * 10) / 10; // 保留一位小数
// 显示结果
this.displayLintResults(score, issues);
}
// 显示测评结果
displayLintResults(score, issues) {
// 更新分数显示
const scoreElement = document.getElementById('code-score');
const qualityElement = document.getElementById('score-quality');
scoreElement.textContent = score.toString();
// 设置质量等级
let qualityText = '优秀';
let qualityClass = 'excellent';
if (score >= 9) {
qualityText = '优秀';
qualityClass = 'excellent';
} else if (score >= 7) {
qualityText = '良好';
qualityClass = 'good';
} else if (score >= 5) {
qualityText = '一般';
qualityClass = 'average';
} else {
qualityText = '需改进';
qualityClass = 'poor';
}
qualityElement.textContent = qualityText;
qualityElement.className = `score-quality ${qualityClass}`;
// 更新CSS样式以反映不同的质量等级
if (qualityClass === 'excellent') {
qualityElement.style.background = 'rgba(0, 255, 0, 0.2)';
qualityElement.style.border = '1px solid rgba(0, 255, 0, 0.3)';
qualityElement.style.color = '#66ff99';
} else if (qualityClass === 'good') {
qualityElement.style.background = 'rgba(0, 212, 255, 0.2)';
qualityElement.style.border = '1px solid rgba(0, 212, 255, 0.3)';
qualityElement.style.color = '#00d4ff';
} else if (qualityClass === 'average') {
qualityElement.style.background = 'rgba(255, 165, 0, 0.2)';
qualityElement.style.border = '1px solid rgba(255, 165, 0, 0.3)';
qualityElement.style.color = '#ffcc66';
} else {
qualityElement.style.background = 'rgba(255, 0, 0, 0.2)';
qualityElement.style.border = '1px solid rgba(255, 0, 0, 0.3)';
qualityElement.style.color = '#ff6b6b';
}
// 更新问题列表
document.getElementById('issues-count').textContent = issues.length.toString();
const issuesList = document.getElementById('issues-list');
if (issues.length === 0) {
issuesList.innerHTML = '<p class="empty-message">代码质量良好,未发现问题</p>';
} else {
// 按行号排序
issues.sort((a, b) => a.line - b.line);
issuesList.innerHTML = issues.map(issue => `
<div class="issue-item">
<div class="issue-header">
<span class="issue-type ${issue.type}">${issue.type === 'error' ? '错误' : issue.type === 'warning' ? '警告' : '信息'}</span>
<span class="issue-line"> ${issue.line} </span>
</div>
<div class="issue-message">${issue.message}</div>
</div>
`).join('');
}
// 生成总结
const summaryElement = document.getElementById('lint-summary');
const errorCount = issues.filter(i => i.type === 'error').length;
const warningCount = issues.filter(i => i.type === 'warning').length;
const infoCount = issues.filter(i => i.type === 'info').length;
summaryElement.innerHTML = `
<ul>
<li><i class="fas fa-check-circle"></i> : ${score}/10 (${qualityText})</li>
<li><i class="fas fa-exclamation-circle"></i> ${errorCount} </li>
<li><i class="fas fa-exclamation-triangle"></i> ${warningCount} </li>
<li><i class="fas fa-info-circle"></i> ${infoCount} </li>
<li><i class="fas fa-code"></i> : ${document.getElementById('python-code-input').value.split('\n').length}</li>
</ul>
<p style="margin-top: 1rem;">
${score >= 7 ? '代码整体质量良好,继续保持!' : '建议根据提示改进代码质量。'}
</p>
`;
}
// 设置事件监听器
setupEventListeners() {
@ -1152,139 +894,93 @@ if __name__ == "__main__":
// 初始化分布图表
initDistributionChart() {
try {
const canvas = document.getElementById('distribution-canvas');
if (!canvas) {
console.warn('Distribution canvas not found');
return;
}
const ctx = canvas.getContext('2d');
if (typeof Chart === 'undefined') {
console.error('Chart.js is not loaded');
// 显示错误信息
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#666';
ctx.font = '14px Arial';
ctx.textAlign = 'center';
ctx.fillText('图表库加载失败', canvas.width/2, canvas.height/2 - 10);
ctx.font = '12px Arial';
ctx.fillText('图表功能暂不可用', canvas.width/2, canvas.height/2 + 10);
return;
}
this.charts.distribution = new Chart(ctx, {
type: 'bar',
data: {
labels: this.mockData.openrankDistribution.map(d => d.range),
datasets: [{
label: '开发者数量',
data: this.mockData.openrankDistribution.map(d => d.count),
backgroundColor: 'rgba(0, 212, 255, 0.6)',
borderColor: 'rgba(0, 212, 255, 1)',
borderWidth: 1
}]
const ctx = document.getElementById('distribution-canvas').getContext('2d');
this.charts.distribution = new Chart(ctx, {
type: 'bar',
data: {
labels: this.mockData.openrankDistribution.map(d => d.range),
datasets: [{
label: '开发者数量',
data: this.mockData.openrankDistribution.map(d => d.count),
backgroundColor: 'rgba(0, 212, 255, 0.6)',
borderColor: 'rgba(0, 212, 255, 1)',
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
labels: {
color: '#ffffff'
}
}
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
labels: {
color: '#ffffff'
}
scales: {
y: {
beginAtZero: true,
grid: {
color: 'rgba(255, 255, 255, 0.1)'
},
ticks: {
color: '#ffffff'
}
},
scales: {
y: {
beginAtZero: true,
grid: {
color: 'rgba(255, 255, 255, 0.1)'
},
ticks: {
color: '#ffffff'
}
x: {
grid: {
color: 'rgba(255, 255, 255, 0.1)'
},
x: {
grid: {
color: 'rgba(255, 255, 255, 0.1)'
},
ticks: {
color: '#ffffff'
}
ticks: {
color: '#ffffff'
}
}
}
});
} catch (error) {
console.error('Error initializing distribution chart:', error);
}
}
});
}
// 初始化活动类型图表
initActivityChart() {
try {
const canvas = document.getElementById('activity-canvas');
if (!canvas) {
console.warn('Activity canvas not found');
return;
}
const ctx = canvas.getContext('2d');
if (typeof Chart === 'undefined') {
console.error('Chart.js is not loaded');
// 显示错误信息
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#666';
ctx.font = '14px Arial';
ctx.textAlign = 'center';
ctx.fillText('图表库加载失败', canvas.width/2, canvas.height/2 - 10);
ctx.font = '12px Arial';
ctx.fillText('图表功能暂不可用', canvas.width/2, canvas.height/2 + 10);
return;
}
this.charts.activity = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ['Issue 评论', '创建 Issue', '创建 PR', '代码评审', '合入 PR'],
datasets: [{
data: [
this.mockData.activityDistribution.issueComment,
this.mockData.activityDistribution.openIssue,
this.mockData.activityDistribution.openPull,
this.mockData.activityDistribution.reviewComment,
this.mockData.activityDistribution.mergedPull
],
backgroundColor: [
'rgba(0, 212, 255, 0.8)',
'rgba(0, 255, 136, 0.8)',
'rgba(255, 193, 7, 0.8)',
'rgba(156, 39, 176, 0.8)',
'rgba(255, 87, 34, 0.8)'
],
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'right',
labels: {
color: '#ffffff',
font: {
size: 12
}
const ctx = document.getElementById('activity-canvas').getContext('2d');
this.charts.activity = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ['Issue 评论', '创建 Issue', '创建 PR', '代码评审', '合入 PR'],
datasets: [{
data: [
this.mockData.activityDistribution.issueComment,
this.mockData.activityDistribution.openIssue,
this.mockData.activityDistribution.openPull,
this.mockData.activityDistribution.reviewComment,
this.mockData.activityDistribution.mergedPull
],
backgroundColor: [
'rgba(0, 212, 255, 0.8)',
'rgba(0, 255, 136, 0.8)',
'rgba(255, 193, 7, 0.8)',
'rgba(156, 39, 176, 0.8)',
'rgba(255, 87, 34, 0.8)'
],
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'right',
labels: {
color: '#ffffff',
font: {
size: 12
}
}
}
}
});
} catch (error) {
console.error('Error initializing activity chart:', error);
}
}
});
}
// 初始化网络图谱

@ -27,7 +27,6 @@
<button class="nav-btn" data-tab="repositories">仓库分析</button>
<button class="nav-btn" data-tab="developers">开发者分析</button>
<button class="nav-btn" data-tab="network">网络图谱</button>
<button class="nav-btn" data-tab="code-review">代码测评</button>
<button class="nav-btn" data-tab="settings">配置</button>
</nav>
<div class="header-actions">
@ -40,61 +39,6 @@
<!-- 主要内容区域 -->
<main class="main-content" id="global-root">
<!-- 代码测评面板 -->
<div class="tab-content" id="code-review">
<div class="code-review-container">
<h2>Python代码测评</h2>
<div class="code-input-section">
<div class="code-editor-controls">
<button id="run-lint-btn" class="btn-primary">
<i class="fas fa-check-circle"></i>
运行Pylint测评
</button>
<button id="clear-code-btn" class="btn-secondary">
<i class="fas fa-trash"></i>
清空代码
</button>
<button id="load-example-btn" class="btn-secondary">
<i class="fas fa-file-code"></i>
加载示例
</button>
</div>
<div class="code-editor-wrapper">
<textarea id="python-code-input" placeholder="请在此输入Python代码...
例如:
def hello():
print('Hello World')
if __name__ == '__main__':
hello()"></textarea>
</div>
</div>
<div class="results-section">
<div class="score-card">
<h3>代码评分</h3>
<div class="score-display">
<span id="code-score">0</span>
<div class="score-label">/ 10</div>
</div>
<div class="score-quality" id="score-quality">待评分</div>
</div>
<div class="issues-container">
<h3>问题列表 <span id="issues-count">0</span></h3>
<div id="issues-list" class="issues-list">
<p class="empty-message">请运行测评查看代码中的问题</p>
</div>
</div>
</div>
<div class="summary-section">
<h3>测评总结</h3>
<div id="lint-summary" class="summary-content">
<p class="empty-message">请运行测评查看代码质量总结</p>
</div>
</div>
</div>
</div>
<!-- 总览面板 -->
<div class="tab-content active" id="overview">
<div class="stats-grid">
@ -355,47 +299,7 @@ if __name__ == '__main__':
</div>
</div>
<!-- Chart.js CDN with fallback -->
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.js"></script>
<script>
// Fallback to local Chart.js if CDN fails
if (typeof Chart === 'undefined') {
document.write('<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.0/chart.umd.js"><\/script>');
}
// Final fallback - load minimal mock if both CDN fail
setTimeout(function() {
if (typeof Chart === 'undefined') {
console.warn('Chart.js failed to load from CDN, creating minimal mock');
window.Chart = function(ctx, config) {
this.ctx = ctx;
this.config = config;
// Mock implementation to prevent errors
this.destroy = function() {};
this.update = function() {};
this.resize = function() {};
// Draw a simple placeholder
if (ctx && ctx.canvas) {
const canvas = ctx.canvas;
const width = canvas.width || 300;
const height = canvas.height || 200;
ctx.clearRect(0, 0, width, height);
ctx.fillStyle = '#666';
ctx.font = '14px Arial';
ctx.textAlign = 'center';
ctx.fillText('Chart.js 加载失败', width/2, height/2 - 10);
ctx.font = '12px Arial';
ctx.fillText('图表功能暂不可用', width/2, height/2 + 10);
}
};
// Mock chart types
Chart.defaults = {};
Chart.controllers = {};
}
}, 3000);
</script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="app.js"></script>
</body>
</html>

@ -98,273 +98,6 @@ body {
.project-header-inline { display:flex; align-items:flex-start; justify-content:space-between; gap:1rem; flex-wrap:wrap; margin-bottom:1rem; }
.project-header-inline h2 { margin:0; font-size:1.25rem; font-weight:700; }
.badge { display:inline-block; padding:.25rem .6rem; font-size:.65rem; letter-spacing:.5px; background:rgba(0,212,255,.15); border:1px solid rgba(0,212,255,.4); border-radius:6px; color:#00d4ff; font-weight:600; }
/* 代码测评页面样式 */
.code-review-container {
padding: 2rem 0;
}
.code-review-container h2 {
font-size: 1.5rem;
font-weight: 700;
margin-bottom: 1.5rem;
color: #ffffff;
}
.code-input-section {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 12px;
padding: 1.5rem;
margin-bottom: 1.5rem;
}
.code-editor-controls {
display: flex;
gap: 1rem;
margin-bottom: 1rem;
flex-wrap: wrap;
}
.btn-secondary {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
color: #ffffff;
padding: 0.5rem 1rem;
border-radius: 8px;
cursor: pointer;
font-weight: 500;
transition: all 0.2s ease;
display: flex;
align-items: center;
gap: 0.5rem;
}
.btn-secondary:hover {
background: rgba(255, 255, 255, 0.15);
border-color: rgba(255, 255, 255, 0.3);
}
.code-editor-wrapper {
position: relative;
}
#python-code-input {
width: 100%;
min-height: 300px;
background: rgba(0, 0, 0, 0.3);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 8px;
color: #ffffff;
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
font-size: 0.9rem;
line-height: 1.5;
padding: 1rem;
resize: vertical;
outline: none;
}
#python-code-input:focus {
border-color: #00d4ff;
box-shadow: 0 0 0 2px rgba(0, 212, 255, 0.25);
}
.results-section {
display: grid;
grid-template-columns: 1fr 3fr;
gap: 1.5rem;
margin-bottom: 1.5rem;
}
.score-card {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 12px;
padding: 1.5rem;
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.score-card h3 {
font-size: 1rem;
font-weight: 600;
margin-bottom: 1rem;
color: rgba(255, 255, 255, 0.8);
}
.score-display {
display: flex;
align-items: baseline;
justify-content: center;
gap: 0.5rem;
margin-bottom: 1rem;
}
#code-score {
font-size: 3rem;
font-weight: 700;
color: #00d4ff;
}
.score-label {
font-size: 1.25rem;
color: rgba(255, 255, 255, 0.6);
}
#score-quality {
font-size: 1rem;
font-weight: 600;
padding: 0.25rem 0.75rem;
border-radius: 6px;
background: rgba(0, 212, 255, 0.2);
border: 1px solid rgba(0, 212, 255, 0.3);
color: #00d4ff;
}
.issues-container {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 12px;
padding: 1.5rem;
}
.issues-container h3 {
font-size: 1rem;
font-weight: 600;
margin-bottom: 1rem;
color: rgba(255, 255, 255, 0.8);
display: flex;
align-items: center;
justify-content: space-between;
}
#issues-count {
font-size: 0.85rem;
padding: 0.2rem 0.5rem;
background: rgba(0, 212, 255, 0.2);
border-radius: 4px;
color: #00d4ff;
}
.issues-list {
max-height: 400px;
overflow-y: auto;
}
.issue-item {
background: rgba(0, 0, 0, 0.2);
border: 1px solid rgba(255, 255, 255, 0.05);
border-radius: 6px;
padding: 0.75rem;
margin-bottom: 0.75rem;
}
.issue-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 0.5rem;
}
.issue-type {
font-size: 0.75rem;
padding: 0.2rem 0.5rem;
border-radius: 4px;
font-weight: 600;
}
.issue-type.error {
background: rgba(255, 0, 0, 0.2);
color: #ff6b6b;
border: 1px solid rgba(255, 0, 0, 0.3);
}
.issue-type.warning {
background: rgba(255, 165, 0, 0.2);
color: #ffcc66;
border: 1px solid rgba(255, 165, 0, 0.3);
}
.issue-type.info {
background: rgba(0, 128, 0, 0.2);
color: #66ff99;
border: 1px solid rgba(0, 128, 0, 0.3);
}
.issue-line {
font-size: 0.75rem;
color: rgba(255, 255, 255, 0.6);
}
.issue-message {
font-size: 0.85rem;
color: rgba(255, 255, 255, 0.8);
line-height: 1.4;
}
.summary-section {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 12px;
padding: 1.5rem;
}
.summary-section h3 {
font-size: 1rem;
font-weight: 600;
margin-bottom: 1rem;
color: rgba(255, 255, 255, 0.8);
}
.summary-content {
font-size: 0.9rem;
line-height: 1.6;
color: rgba(255, 255, 255, 0.7);
}
.summary-content ul {
list-style: none;
padding: 0;
}
.summary-content li {
margin-bottom: 0.75rem;
display: flex;
align-items: flex-start;
gap: 0.75rem;
}
.summary-content li i {
color: #00d4ff;
margin-top: 0.25rem;
min-width: 16px;
}
.empty-message {
color: rgba(255, 255, 255, 0.5);
font-style: italic;
text-align: center;
padding: 2rem 0;
}
/* 响应式设计 */
@media (max-width: 768px) {
.results-section {
grid-template-columns: 1fr;
}
.code-editor-controls {
flex-direction: column;
}
.btn-primary, .btn-secondary {
width: 100%;
justify-content: center;
}
}
.badge.approx { background:rgba(255,193,7,.15); border-color:rgba(255,193,7,.4); color:#ffc107; }
.badge.full { background:rgba(0,255,136,.15); border-color:rgba(0,255,136,.4); color:#00ff88; }

@ -1,159 +0,0 @@
@startuml
!theme vibrant
title ER Diagram for "OpenRank Database System"
entity "repos" as Repos {
-- Fields --
* id : BIGINT <<PK>>
platform : VARCHAR(32)
full_name : VARCHAR(255)
owner : VARCHAR(128)
name : VARCHAR(128)
language : VARCHAR(64)
description : TEXT
stars : INT
forks : INT
metadata : JSON
updated_at : DATETIME
}
entity "issues" as Issues {
-- Fields --
* id : BIGINT <<PK>>
platform : VARCHAR(32)
repo_id : BIGINT
repo_full_name : VARCHAR(255)
number : INT
title : TEXT
body_long : LONGTEXT
author_id : BIGINT
author_login : VARCHAR(128)
state : VARCHAR(32)
created_at : DATETIME
closed_at : DATETIME
labels : JSON
assignees : JSON
first_response_hours : INT
assignment_type : VARCHAR(32)
reactions : JSON
activities_count : INT
raw_payload : JSON
updated_at : DATETIME
}
entity "pull_requests" as PullRequests {
-- Fields --
* id : BIGINT <<PK>>
platform : VARCHAR(32)
repo_id : BIGINT
repo_full_name : VARCHAR(255)
number : INT
title : TEXT
body_long : LONGTEXT
author_id : BIGINT
author_login : VARCHAR(128)
state : VARCHAR(32)
created_at : DATETIME
merged_at : DATETIME
closed_at : DATETIME
labels : JSON
milestone_due : DATETIME
first_response_hours : INT
reactions : JSON
files_changed : INT
additions : INT
deletions : INT
test_files_changed : INT
coverage_delta : FLOAT
core_file_ratio : FLOAT
ci_status : VARCHAR(64)
change_requests : INT
reopened : TINYINT(1)
reverted : TINYINT(1)
activities_count : INT
raw_payload : JSON
updated_at : DATETIME
}
entity "activities" as Activities {
-- Fields --
* item_type : ENUM('issue','pr') <<PK>>
* item_id : BIGINT <<PK>>
* actor_id : BIGINT <<PK>>
platform : VARCHAR(32)
repo_id : BIGINT
item_number : INT
actor_login : VARCHAR(255)
open_count : INT
comment_count : INT
review_count : INT
close_count : INT
review_comment_count : INT
commit_count : INT
activity_meta : JSON
created_at : TIMESTAMP
updated_at : TIMESTAMP
}
entity "repo_events" as RepoEvents {
-- Fields --
* id : BIGINT <<PK>>
platform : VARCHAR(32)
repo_id : BIGINT
actor_id : BIGINT
actor_login : VARCHAR(128)
event_type : VARCHAR(32)
count : INT
event_time : DATETIME
created_at : DATETIME
}
entity "raw_payloads" as RawPayloads {
-- Fields --
* id : BIGINT <<PK>>
platform : VARCHAR(32)
repo_id : BIGINT
resource_type : VARCHAR(32)
resource_id : BIGINT
payload : JSON
fetched_at : DATETIME
}
entity "fetch_runs" as FetchRuns {
-- Fields --
* id : BIGINT <<PK>>
platform : VARCHAR(32)
repo_id : BIGINT
repo_full_name : VARCHAR(255)
source : ENUM('network','db')
start_time : DATETIME
end_time : DATETIME
start_date : DATE
end_date : DATE
token_used : TINYINT(1)
success : TINYINT(1)
note : TEXT
stats : JSON
created_at : DATETIME
issues : INT
pull_requests : INT
activities : INT
meta : JSON
}
' 关系定义一个仓库可以有多个issues、pull_requests、activities等
Repos ||--o{ Issues : "repo_id"}
Repos ||--o{ PullRequests : "repo_id"}
Repos ||--o{ Activities : "repo_id"}
Repos ||--o{ RepoEvents : "repo_id"}
Repos ||--o{ RawPayloads : "repo_id"}
Repos ||--o{ FetchRuns : "repo_id"}
' activities表通过复合主键关联issues和pull_requests
Issues ||--o{ Activities : "item_id (item_type='issue')"}
PullRequests ||--o{ Activities : "item_id (item_type='pr')"}
' fetch_runs表记录数据抓取任务与仓库关联
@enduml

@ -1,90 +0,0 @@
classDiagram
direction TB
class OpenRankDashboard {
-currentTab: string
-mode: string
-charts: object
-mockData: object
-projectState: object
+init()
+setupEventListeners()
+setupTabNavigation()
+switchTab(tab: string)
+switchMode(mode: string)
+loadMockData()
+initCharts()
+generateMockData()
}
class Overview {
+updateStats()
+updateRankingTable()
+initDistributionChart()
+initActivityChart()
}
class Repositories {
+updateRepositoryGrid()
+filterRepositories(filter: string)
+onViewRepoDetails(repoName: string)
+onViewRepoContributions(repoName: string)
+showRepoDetails(owner: string, repo: string)
}
class Developers {
+displayDeveloperAnalysis(developers: array)
+filterDevelopers(keyword: string)
}
class Network {
+initNetworkGraph()
}
class CodeReview {
+setupCodeReviewPage()
+loadExampleCode()
+runCodeLinting()
+simulatePylintAnalysis(code: string)
+displayLintResults(score: number, issues: array)
+resetCodeReviewResults()
}
class Settings {
+setupConfigListeners()
+updateConfig(id: string, value: any)
}
class ProjectMode {
+buildProjectListFromGlobal()
+renderProjectList(keyword: string)
+renderApproxProject(fullName: string, days: number)
+mountProjectView(snapshot: object)
+triggerFullProjectCalculation(fullName: string)
+autoTriggerFull(fullName: string, days: number)
+pollTask(taskId: string, fullName: string, silent: boolean)
}
OpenRankDashboard --> Overview: contains
OpenRankDashboard --> Repositories: contains
OpenRankDashboard --> Developers: contains
OpenRankDashboard --> Network: contains
OpenRankDashboard --> CodeReview: contains
OpenRankDashboard --> Settings: contains
OpenRankDashboard --> ProjectMode: contains
class DataLoader {
+fetchProjectOverview(owner: string, repo: string)
+fetchRepoDetails(owner: string, repo: string)
+fetchContributors(owner: string, repo: string)
}
class UIHelper {
+showNotification(message: string, type: string)
+updateLastUpdateTime()
+pushURLState()
+hydrateFromURL()
}
OpenRankDashboard --> DataLoader: uses
OpenRankDashboard --> UIHelper: uses

@ -1,166 +0,0 @@
classDiagram
direction TB
%% 核心算法类
class OpenRankCalculator {
- config: OpenRankConfig
- graph: Graph
- calculationStatus: CalculationStatus
+ calculate(activityData: ActivityData[], lastMonthOpenRank: Map~string, number~): Promise~OpenRankResult[]~
- buildGraph(activityData: ActivityData[], lastMonthOpenRank: Map~string, number~): void
- iterativeCalculation(): Promise~void~
- generateResults(): OpenRankResult[]
+ getCalculationStatus(): CalculationStatus
+ getGraphStats()
+ cleanup(): void
}
class ProjectOpenRankCalculator {
- config: OpenRankConfig
- graph: Graph
- calculationStatus: CalculationStatus
- weightingFramework: WeightingFramework
+ calculateProjectOpenRank(issueData: IssueData[], pullRequestData: PullRequestData[], lastMonthOpenRank: Map~string, number~, repoEvents?: RepoEventActivity[]): Promise~OpenRankResult[]~
- buildProjectGraph(issueData: IssueData[], pullRequestData: PullRequestData[], lastMonthOpenRank: Map~string, number~, repoEvents?: RepoEventActivity[]): void
- computeCodeImpactPools(pr: any, totalLines: number, filesChanged: number, ...): object
}
class SimpleGraph {
+ nodes: Map~string, GraphNode~
+ edges: GraphEdge[]
- adjacencyList: Map~string, Set~string~~
- incomingEdges: Map~string, GraphEdge[]~
- outgoingEdges: Map~string, GraphEdge[]~
+ addNode(node: GraphNode): void
+ addEdge(edge: GraphEdge): void
+ getNode(id: string): GraphNode | undefined
+ getNeighbors(nodeId: string): GraphNode[]
+ getIncomingEdges(nodeId: string): GraphEdge[]
+ getOutgoingEdges(nodeId: string): GraphEdge[]
+ clear(): void
+ getStats()
+ isConnected(): boolean
+ getDegree(nodeId: string)
+ getNodesByType(type: string): GraphNode[]
}
%% 数据收集类
class ProjectData {
issues: IssueData[]
pullRequests: PullRequestData[]
}
class GitHubDataCollector {
- config: GitHubConfig
- baseUrl: string
+ collectProjectData(repo: GitHubRepo, startDate: Date, endDate: Date): Promise~ProjectData~
- listIssues(repo: GitHubRepo, startDate: Date, endDate: Date): Promise~number[]~
- listPulls(repo: GitHubRepo, startDate: Date, endDate: Date): Promise~number[]~
- collectIssueData(repo: GitHubRepo, issueIds: number[], events: any[]): Promise~IssueData[]~
- collectPullRequestData(repo: GitHubRepo, prIds: number[], events: any[]): Promise~PullRequestData[]~
}
%% API服务类
class APIServer {
- app: Express.Application
- calculationCache: Record~string, CalcCacheEntry~
- projectCache: Record~string, ProjectSnapshotCacheEntry~
- tasks: Record~string, TaskEntry~
+ start(): void
- cleanupCaches(): void
- createTask(): TaskEntry
- getTask(id: string): TaskEntry | null
- updateTask(id: string, patch: Partial~TaskEntry~): void
}
%% 数据库类
class MySQLConnection {
+ pool: Pool
+ closePool(): Promise~void~
}
%% 接口和类型
class ActivityData {
platform: PlatformType
repoId: number
repoName: string
orgId?: number
orgName?: string
actorId: number
actorLogin: string
issueComment: number
openIssue: number
openPull: number
reviewComment: number
mergedPull: number
createdAt: Date
}
class IssueData {
id: number
number?: number
platform: PlatformType
repoId: number
repoName: string
title: string
authorId: number
authorLogin: string
createdAt: Date
closedAt?: Date
state: 'open' | 'closed'
activities: any[]
reactions: any
}
class PullRequestData {
id: number
number?: number
platform: PlatformType
repoId: number
repoName: string
title: string
authorId: number
authorLogin: string
createdAt: Date
mergedAt?: Date
closedAt?: Date
state: 'open' | 'closed' | 'merged'
activities: any[]
reactions: any
filesChanged?: number
additions?: number
deletions?: number
}
class GraphNode {
id: string
type: NodeType
platform: PlatformType
name: string
openrank: number
lastOpenrank: number
initValue: number
retentionFactor: number
converged: boolean
metadata?: Record~string, any~
}
class GraphEdge {
source: string
target: string
weight: number
type: 'activity' | 'belong' | 'reverse_belong' | 'reverse_activity'
activityDetails?: any
}
%% 关系
OpenRankCalculator --> SimpleGraph: uses
ProjectOpenRankCalculator --> SimpleGraph: uses
APIServer --> OpenRankCalculator: calls
APIServer --> ProjectOpenRankCalculator: calls
APIServer --> GitHubDataCollector: uses
APIServer --> MySQLConnection: uses
OpenRankCalculator --> ActivityData: processes
ProjectOpenRankCalculator --> IssueData: processes
ProjectOpenRankCalculator --> PullRequestData: processes
SimpleGraph --> GraphNode: contains
SimpleGraph --> GraphEdge: contains

@ -1,58 +0,0 @@
@startuml
skinparam class {
BackgroundColor<<boundary>> LightSkyBlue
BackgroundColor<<control>> LightGreen
BackgroundColor<<entity>> Gold
}
class MainUI <<boundary>> {
- algorithmController: AlgorithmController
- chartController: ChartController
+ startPage()
+ displayDataAndChart(data: ProjectData, chart: Chart)
+ openOpenRankSegment()
}
class AlgorithmController <<control>> {
- database: DateBase
+ getProjectData(): ProjectData
}
class ChartController <<control>> {
+ generateChart(data: ProjectData): Chart
}
class DateBase <<entity>> {
- projectData: List<ProjectData>
+ getProjectData(): ProjectData
}
class ProjectData <<entity>> {
- id: String
- name: String
- openRankData: List<Double>
+ getId(): String
+ getName(): String
+ getOpenRankData(): List<Double>
}
class Chart <<entity>> {
- type: String
- data: Object
- title: String
+ render(): void
+ getType(): String
}
' 关联关系
MainUI --> AlgorithmController : "调用"
MainUI --> ChartController : "调用"
AlgorithmController --> DateBase : "查询"
AlgorithmController ..> ProjectData : "返回"
ChartController ..> Chart : "生成"
DateBase "1" *-- "many" ProjectData : "包含"
@enduml

@ -1,135 +0,0 @@
@startuml
skinparam class {
BackgroundColor<<boundary>> LightSkyBlue
BackgroundColor<<control>> LightGreen
BackgroundColor<<entity>> Gold
}
class MainUI <<boundary>> {
- checkUI: CheckUI
+ startPage()
+ showMainInterface()
+ navigateToCodeAssessmentPage()
}
class CheckUI <<boundary>> {
- pylint: Pylint
- currentAssessment: CodeAssessment
+ showCodeAssessmentPage()
+ uploadCodeToBeTested(code: CodeFile): boolean
+ displayAssessmentResult(result: AssessmentResult)
}
class Pylint <<control>> {
- database: DateBase
+ assessCodeQuality(code: CodeFile): AssessmentResult
+ generateQualityReport(assessment: AssessmentResult): QualityReport
}
class DateBase <<entity>> {
- codeAssessments: List<CodeAssessment>
- qualityScores: List<QualityScore>
- assessmentHistory: List<AssessmentHistory>
+ storeCodeScore(assessment: CodeAssessment): boolean
+ getAssessmentHistory(codeId: String): List<AssessmentHistory>
+ getAverageQualityScore(projectId: String): double
}
class CodeFile <<entity>> {
- codeId: String
- fileName: String
- filePath: String
- language: String
- content: String
- size: long
+ getCodeId(): String
+ getFileName(): String
+ getLanguage(): String
+ getContent(): String
}
class AssessmentResult <<entity>> {
- assessmentId: String
- codeId: String
- qualityScore: double
- issues: List<CodeIssue>
- assessmentTime: Date
+ getQualityScore(): double
+ getIssues(): List<CodeIssue>
+ generateSummary(): String
}
class CodeAssessment <<entity>> {
- assessmentId: String
- codeFile: CodeFile
- result: AssessmentResult
- assessmentDate: Date
+ getAssessmentId(): String
+ getAssessmentDate(): Date
+ getResult(): AssessmentResult
}
class CodeIssue <<entity>> {
- issueId: String
- type: String
- severity: String
- lineNumber: int
- description: String
- suggestion: String
+ getIssueId(): String
+ getType(): String
+ getSeverity(): String
+ getDescription(): String
}
class QualityScore <<entity>> {
- scoreId: String
- codeId: String
- overallScore: double
- maintainabilityScore: double
- reliabilityScore: double
- efficiencyScore: double
+ getOverallScore(): double
+ getMaintainabilityScore(): double
+ calculateCompositeScore(): double
}
class QualityReport <<entity>> {
- reportId: String
- assessmentId: String
- summary: String
- detailedAnalysis: String
- recommendations: List<String>
+ generateReport(): String
+ exportAsPDF(): void
}
class AssessmentHistory <<entity>> {
- historyId: String
- codeId: String
- assessmentDate: Date
- qualityScore: double
- trend: String
+ getHistoryId(): String
+ getAssessmentDate(): Date
+ getQualityScore(): double
+ calculateTrend(): String
}
' 关联关系
MainUI --> CheckUI : "跳转"
CheckUI --> Pylint : "调用测评"
Pylint --> DateBase : "存储分数"
Pylint ..> AssessmentResult : "生成"
DateBase "1" *-- "many" CodeAssessment : "存储"
DateBase "1" *-- "many" QualityScore : "包含"
DateBase "1" *-- "many" AssessmentHistory : "记录历史"
CodeAssessment "1" *-- "1" CodeFile : "测评"
CodeAssessment "1" *-- "1" AssessmentResult : "包含结果"
AssessmentResult "1" *-- "many" CodeIssue : "包含问题"
AssessmentResult "1" *-- "1" QualityScore : "关联分数"
Pylint ..> QualityReport : "生成报告"
@enduml

@ -1,141 +0,0 @@
@startuml
skinparam class {
BackgroundColor<<boundary>> LightSkyBlue
BackgroundColor<<control>> LightGreen
BackgroundColor<<entity>> Gold
}
class MainUI <<boundary>> {
- webUI: WebUI
+ startPage()
+ showMainInterface()
+ navigateToNetworkGraphPage()
}
class WebUI <<boundary>> {
- algorithmController: AlgorithmController
- chartController: ChartController
+ showNetworkGraphPage()
+ displayNetworkGraph(graph: NetworkGraph)
}
class AlgorithmController <<control>> {
- database: DateBase
+ getNetworkGraphData(): NetworkData
}
class ChartController <<control>> {
+ drawNetworkGraph(data: NetworkData): NetworkGraph
}
class DateBase <<entity>> {
- developerData: List<DeveloperData>
- projectData: List<ProjectData>
- relationshipData: List<RelationshipData>
+ getDeveloperData(): List<DeveloperData>
+ getProjectData(): List<ProjectData>
+ getRelationshipData(): List<RelationshipData>
}
class NetworkData <<entity>> {
- developers: List<DeveloperData>
- projects: List<ProjectData>
- relationships: List<RelationshipData>
+ getDevelopers(): List<DeveloperData>
+ getProjects(): List<ProjectData>
+ getRelationships(): List<RelationshipData>
}
class NetworkGraph <<entity>> {
- graphId: String
- graphType: String
- nodes: List<GraphNode>
- edges: List<GraphEdge>
- layout: GraphLayout
+ render(): void
+ exportAsImage(format: String): void
+ getGraphData(): Object
}
class DeveloperData <<entity>> {
- developerId: String
- name: String
- avatar: String
- projects: List<String>
+ getDeveloperId(): String
+ getName(): String
+ getProjects(): List<String>
}
class ProjectData <<entity>> {
- projectId: String
- name: String
- description: String
- contributors: List<String>
+ getProjectId(): String
+ getName(): String
+ getContributors(): List<String>
}
class RelationshipData <<entity>> {
- sourceId: String
- targetId: String
- relationshipType: String
- strength: double
+ getSourceId(): String
+ getTargetId(): String
+ getRelationshipType(): String
+ getStrength(): double
}
class GraphNode <<entity>> {
- nodeId: String
- nodeType: String
- label: String
- position: Point
- properties: Map<String, Object>
+ getNodeId(): String
+ getLabel(): String
+ getPosition(): Point
}
class GraphEdge <<entity>> {
- edgeId: String
- sourceNodeId: String
- targetNodeId: String
- weight: double
- label: String
+ getSourceNodeId(): String
+ getTargetNodeId(): String
+ getWeight(): double
}
class GraphLayout <<entity>> {
- layoutType: String
- parameters: Map<String, Object>
- nodePositions: Map<String, Point>
+ calculateLayout(nodes: List<GraphNode>, edges: List<GraphEdge>): void
+ getNodePosition(nodeId: String): Point
}
' 关联关系
MainUI --> WebUI : "跳转"
WebUI --> AlgorithmController : "调用"
WebUI --> ChartController : "调用"
AlgorithmController --> DateBase : "查询"
AlgorithmController ..> NetworkData : "返回"
ChartController ..> NetworkGraph : "生成"
DateBase "1" *-- "many" DeveloperData : "包含"
DateBase "1" *-- "many" ProjectData : "包含"
DateBase "1" *-- "many" RelationshipData : "包含"
NetworkData "1" *-- "many" DeveloperData : "包含"
NetworkData "1" *-- "many" ProjectData : "包含"
NetworkData "1" *-- "many" RelationshipData : "包含"
NetworkGraph "1" *-- "many" GraphNode : "包含"
NetworkGraph "1" *-- "many" GraphEdge : "包含"
NetworkGraph "1" *-- "1" GraphLayout : "使用"
@enduml

@ -1,126 +0,0 @@
@startuml
skinparam class {
BackgroundColor<<boundary>> LightSkyBlue
BackgroundColor<<control>> LightGreen
BackgroundColor<<entity>> Gold
}
class MainUI <<boundary>> {
- dateController: DateController
+ startPage()
+ showMainInterface()
+ displayPRData(prData: List<PullRequestData>)
+ displayIssueData(issueData: List<IssueData>)
}
class DateController <<control>> {
- githubApi: GithubApi
- database: DateBase
+ getProjectIssueData(): List<IssueData>
+ getProjectPRData(): List<PullRequestData>
+ storeIssueData(issueData: List<IssueData>): boolean
+ storePRData(prData: List<PullRequestData>): boolean
}
class GithubApi <<boundary>> {
- apiKey: String
- baseUrl: String
+ requestProjectIssueData(projectId: String): List<IssueData>
+ requestProjectPRData(projectId: String): List<PullRequestData>
+ authenticate(apiKey: String): boolean
}
class DateBase <<entity>> {
- issueData: List<IssueData>
- prData: List<PullRequestData>
- projects: List<Project>
+ storeIssueData(issueData: List<IssueData>): boolean
+ storePRData(prData: List<PullRequestData>): boolean
+ getIssueData(projectId: String): List<IssueData>
+ getPRData(projectId: String): List<PullRequestData>
}
class IssueData <<entity>> {
- issueId: String
- projectId: String
- title: String
- state: String
- creator: String
- createdAt: Date
- closedAt: Date
- labels: List<String>
- commentsCount: int
+ getIssueId(): String
+ getProjectId(): String
+ getState(): String
+ calculateDuration(): long
+ isClosed(): boolean
}
class PullRequestData <<entity>> {
- prId: String
- projectId: String
- title: String
- state: String
- author: String
- createdAt: Date
- mergedAt: Date
- closedAt: Date
- reviewComments: int
- commits: int
+ getPRId(): String
+ getProjectId(): String
+ getState(): String
+ isMerged(): boolean
+ calculateMergeTime(): long
}
class Project <<entity>> {
- projectId: String
- name: String
- repositoryUrl: String
- description: String
+ getProjectId(): String
+ getName(): String
+ getRepositoryUrl(): String
}
class IssueStatistics <<entity>> {
- projectId: String
- totalIssues: int
- openIssues: int
- closedIssues: int
- averageResolutionTime: double
- issueTrend: Map<Date, int>
+ calculateStatistics(issueData: List<IssueData>): void
+ getOpenIssueCount(): int
+ getClosedIssueCount(): int
}
class PRStatistics <<entity>> {
- projectId: String
- totalPRs: int
- openPRs: int
- mergedPRs: int
- averageMergeTime: double
- prTrend: Map<Date, int>
+ calculateStatistics(prData: List<PullRequestData>): void
+ getMergedPRCount(): int
+ getOpenPRCount(): int
}
' 关联关系
MainUI --> DateController : "调用"
DateController --> GithubApi : "请求数据"
DateController --> DateBase : "存储/查询"
GithubApi ..> IssueData : "返回"
GithubApi ..> PullRequestData : "返回"
DateBase "1" *-- "many" IssueData : "存储"
DateBase "1" *-- "many" PullRequestData : "存储"
DateBase "1" *-- "many" Project : "包含"
IssueStatistics ..> IssueData : "分析"
PRStatistics ..> PullRequestData : "分析"
@enduml

@ -1,163 +0,0 @@
@startuml
skinparam class {
BackgroundColor<<boundary>> LightSkyBlue
BackgroundColor<<control>> LightGreen
BackgroundColor<<entity>> Gold
}
class MainUI <<boundary>> {
- dateController: DateController
+ startPage()
+ showMainInterface()
+ displayDeveloperData(developerData: List<DeveloperData>)
+ displayRepositoryData(repositoryData: List<RepositoryData>)
}
class DateController <<control>> {
- githubApi: GithubApi
- database: DateBase
+ getProjectDeveloperData(): List<DeveloperData>
+ getRepositoryData(): List<RepositoryData>
+ storeProjectDeveloperData(developerData: List<DeveloperData>): boolean
+ storeRepositoryData(repositoryData: List<RepositoryData>): boolean
}
class GithubApi <<boundary>> {
- apiKey: String
- baseUrl: String
+ requestProjectDeveloperData(projectId: String): List<DeveloperData>
+ requestRepositoryData(projectId: String): List<RepositoryData>
+ authenticate(apiKey: String): boolean
}
class DateBase <<entity>> {
- developerData: List<DeveloperData>
- repositoryData: List<RepositoryData>
- organizations: List<Organization>
+ storeProjectDeveloperData(developerData: List<DeveloperData>): boolean
+ storeRepositoryData(repositoryData: List<RepositoryData>): boolean
+ getDeveloperData(projectId: String): List<DeveloperData>
+ getRepositoryData(organizationId: String): List<RepositoryData>
}
class DeveloperData <<entity>> {
- developerId: String
- username: String
- email: String
- organization: String
- repositories: List<String>
- joinDate: Date
+ getDeveloperId(): String
+ getUsername(): String
+ getOrganization(): String
+ getRepositories(): List<String>
}
class RepositoryData <<entity>> {
- repositoryId: String
- name: String
- description: String
- organization: String
- createdAt: Date
- lastUpdated: Date
- language: String
+ getRepositoryId(): String
+ getName(): String
+ getOrganization(): String
+ getLanguage(): String
}
class Organization <<entity>> {
- organizationId: String
- name: String
- description: String
- memberCount: int
- repositoryCount: int
+ getOrganizationId(): String
+ getName(): String
+ getMemberCount(): int
+ getRepositoryCount(): int
}
class DeveloperStatistics <<entity>> {
- organizationId: String
- totalDevelopers: int
- activeDevelopers: int
- newDevelopersThisMonth: int
- developerGrowthRate: double
- topLanguages: Map<String, int>
+ calculateStatistics(developerData: List<DeveloperData>): void
+ getTotalDevelopers(): int
+ getDeveloperGrowthRate(): double
}
class RepositoryStatistics <<entity>> {
- organizationId: String
- totalRepositories: int
- publicRepositories: int
- privateRepositories: int
- newRepositoriesThisMonth: int
- repositoryGrowthRate: double
- topLanguages: Map<String, int>
+ calculateStatistics(repositoryData: List<RepositoryData>): void
+ getTotalRepositories(): int
+ getRepositoryGrowthRate(): double
}
class LanguageStatistics <<entity>> {
- language: String
- developerCount: int
- repositoryCount: int
- popularityScore: double
+ getLanguage(): String
+ getDeveloperCount(): int
+ getRepositoryCount(): int
+ calculatePopularityScore(): double
}
' 关联关系
MainUI --> DateController : "调用"
DateController --> GithubApi : "请求数据"
DateController --> DateBase : "存储/查询"
GithubApi ..> DeveloperData : "返回"
GithubApi ..> RepositoryData : "返回"
DateBase "1" *-- "many" DeveloperData : "存储"
DateBase "1" *-- "many" RepositoryData : "存储"
DateBase "1" *-- "many" Organization : "包含"
DeveloperStatistics ..> DeveloperData : "分析"
RepositoryStatistics ..> RepositoryData : "分析"
LanguageStatistics ..> DeveloperData : "关联"
LanguageStatistics ..> RepositoryData : "关联"
note right of DateController::getProjectDeveloperData
获取项目开发者数据
包括从API获取和存储
end note
note right of DateController::getRepositoryData
获取仓库数据
包括从API获取和存储
end note
note right of GithubApi::requestProjectDeveloperData
调用GitHub API
获取项目开发者数据
end note
note right of GithubApi::requestRepositoryData
调用GitHub API
获取仓库数据
end note
note right of DeveloperStatistics::calculateStatistics
计算开发者统计信息
包括数量和增长率
end note
note right of RepositoryStatistics::calculateStatistics
计算仓库统计信息
包括数量和增长率
end note
@enduml

@ -1,143 +0,0 @@
@startuml
skinparam class {
BackgroundColor<<boundary>> LightSkyBlue
BackgroundColor<<control>> LightGreen
BackgroundColor<<entity>> Gold
}
class MainUI <<boundary>> {
- dateController: DateController
+ startPage()
+ showMainInterface()
+ displayCommitData(commitData: List<CommitData>)
+ displayRepositoryStarData(starData: List<RepositoryStarData>)
}
class DateController <<control>> {
- githubApi: GithubApi
- database: DateBase
+ getRepositoryStarData(): List<RepositoryStarData>
+ getCommitData(): List<CommitData>
+ storeRepositoryStarData(starData: List<RepositoryStarData>): boolean
+ storeCommitData(commitData: List<CommitData>): boolean
}
class GithubApi <<boundary>> {
- apiKey: String
- baseUrl: String
+ requestRepositoryStarData(projectId: String): List<RepositoryStarData>
+ requestCommitData(projectId: String): List<CommitData>
+ authenticate(apiKey: String): boolean
}
class DateBase <<entity>> {
- repositoryStarData: List<RepositoryStarData>
- commitData: List<CommitData>
- projects: List<Project>
+ storeRepositoryStarData(starData: List<RepositoryStarData>): boolean
+ storeCommitData(commitData: List<CommitData>): boolean
+ getRepositoryStarData(projectId: String): List<RepositoryStarData>
+ getCommitData(projectId: String): List<CommitData>
}
class RepositoryStarData <<entity>> {
- repositoryId: String
- starCount: int
- stargazers: List<Stargazer>
- starHistory: Map<Date, int>
- date: Date
+ getRepositoryId(): String
+ getStarCount(): int
+ getStargazers(): List<Stargazer>
+ calculateStarGrowth(startDate: Date, endDate: Date): int
}
class CommitData <<entity>> {
- commitId: String
- repositoryId: String
- author: String
- date: Date
- message: String
- filesChanged: int
- linesAdded: int
- linesDeleted: int
+ getCommitId(): String
+ getRepositoryId(): String
+ getAuthor(): String
+ getDate(): Date
+ getChangeSummary(): String
}
class Project <<entity>> {
- projectId: String
- name: String
- repositoryUrl: String
- description: String
+ getProjectId(): String
+ getName(): String
+ getRepositoryUrl(): String
}
class Stargazer <<entity>> {
- userId: String
- username: String
- starredAt: Date
+ getUserId(): String
+ getUsername(): String
+ getStarredAt(): Date
}
class StarStatistics <<entity>> {
- repositoryId: String
- totalStars: int
- starsThisMonth: int
- starsThisYear: int
- starGrowthRate: double
- topStargazers: List<Stargazer>
+ calculateStatistics(starData: List<RepositoryStarData>): void
+ getStarGrowthRate(): double
+ getTopStargazers(count: int): List<Stargazer>
}
class CommitStatistics <<entity>> {
- repositoryId: String
- totalCommits: int
- commitsThisMonth: int
- commitsThisYear: int
- topContributors: List<Contributor>
- commitFrequency: Map<Date, int>
+ calculateStatistics(commitData: List<CommitData>): void
+ getTotalCommits(): int
+ getTopContributors(count: int): List<Contributor>
}
class Contributor <<entity>> {
- contributorId: String
- username: String
- commitCount: int
- firstCommit: Date
- lastCommit: Date
+ getContributorId(): String
+ getUsername(): String
+ getCommitCount(): int
+ getActivityPeriod(): TimeSpan
}
' 关联关系
MainUI --> DateController : "调用"
DateController --> GithubApi : "请求数据"
DateController --> DateBase : "存储/查询"
GithubApi ..> RepositoryStarData : "返回"
GithubApi ..> CommitData : "返回"
DateBase "1" *-- "many" RepositoryStarData : "存储"
DateBase "1" *-- "many" CommitData : "存储"
DateBase "1" *-- "many" Project : "包含"
RepositoryStarData "1" *-- "many" Stargazer : "包含"
StarStatistics ..> RepositoryStarData : "分析"
CommitStatistics ..> CommitData : "分析"
CommitStatistics "1" *-- "many" Contributor : "统计"
@enduml

@ -1,102 +0,0 @@
@startuml
skinparam class {
BackgroundColor<<boundary>> LightSkyBlue
BackgroundColor<<control>> LightGreen
BackgroundColor<<entity>> Gold
}
class MainUI <<boundary>> {
- codehubUI: CodehubUI
+ startPage()
+ showMainInterface()
+ navigateToRepositoryAnalysis()
}
class CodehubUI <<boundary>> {
- algorithmController: AlgorithmController
+ showRepositoryAnalysisPage()
+ displayRepositoryAnalysisResult(result: RepositoryAnalysisResult)
}
class AlgorithmController <<control>> {
- database: DateBase
- pylint: Pylint
+ getRepositoryCodeData(): RepositoryAnalysisResult
}
class Pylint <<control>> {
+ analyzeRepository(codeData: RepositoryCodeData): RepositoryAnalysisResult
}
class DateBase <<entity>> {
- repositoryData: List<RepositoryCodeData>
+ getRepositoryCodeData(): RepositoryCodeData
}
class RepositoryCodeData <<entity>> {
- repositoryId: String
- repositoryName: String
- codeFiles: List<CodeFile>
- commitHistory: List<Commit>
- contributors: List<Contributor>
+ getRepositoryId(): String
+ getRepositoryName(): String
+ getCodeFiles(): List<CodeFile>
+ getCommitHistory(): List<Commit>
}
class RepositoryAnalysisResult <<entity>> {
- repositoryId: String
- repositoryName: String
- qualityScore: double
- activityScore: double
- communityScore: double
- overallScore: double
- analysisMetrics: Map<String, Object>
+ getOverallScore(): double
+ getDetailedScores(): Map<String, double>
+ generateReport(): String
}
class CodeFile <<entity>> {
- fileName: String
- filePath: String
- language: String
- size: long
- complexity: int
+ getComplexity(): int
+ getLanguage(): String
}
class Commit <<entity>> {
- commitId: String
- author: String
- date: Date
- message: String
- changes: int
+ getAuthor(): String
+ getChanges(): int
}
class Contributor <<entity>> {
- contributorId: String
- name: String
- commitCount: int
+ getCommitCount(): int
}
' 关联关系
MainUI --> CodehubUI : "跳转"
CodehubUI --> AlgorithmController : "调用"
AlgorithmController --> DateBase : "查询"
AlgorithmController --> Pylint : "委托分析"
Pylint ..> RepositoryAnalysisResult : "生成"
DateBase "1" *-- "many" RepositoryCodeData : "包含"
RepositoryCodeData "1" *-- "many" CodeFile : "包含"
RepositoryCodeData "1" *-- "many" Commit : "包含"
RepositoryCodeData "1" *-- "many" Contributor : "包含"
@enduml

@ -1,76 +0,0 @@
@startuml
skinparam class {
BackgroundColor<<boundary>> LightSkyBlue
BackgroundColor<<control>> LightGreen
BackgroundColor<<entity>> Gold
}
class MainUI <<boundary>> {
- developerUI: DeveloperUI
+ startPage()
+ showMainInterface()
+ navigateToDeveloperAnalysis()
}
class DeveloperUI <<boundary>> {
- algorithmController: AlgorithmController
+ showDeveloperAnalysisPage()
+ displayDeveloperAnalysisResult(result: DeveloperAnalysisResult)
}
class AlgorithmController <<control>> {
- database: DateBase
+ getDeveloperContributionData(): DeveloperAnalysisResult
}
class DateBase <<entity>> {
- developerData: List<DeveloperData>
+ getDeveloperData(): DeveloperData
}
class DeveloperData <<entity>> {
- developerId: String
- developerName: String
- contributions: List<Contribution>
- commitCount: int
- codeLines: int
+ getDeveloperId(): String
+ getDeveloperName(): String
+ getContributions(): List<Contribution>
+ calculateContributionScore(): double
}
class DeveloperAnalysisResult <<entity>> {
- developerId: String
- developerName: String
- contributionScore: double
- analysisDetails: Map<String, Object>
- ranking: int
+ getContributionScore(): double
+ getAnalysisDetails(): Map<String, Object>
+ getRanking(): int
+ generateReport(): String
}
class Contribution <<entity>> {
- type: String
- value: double
- date: Date
+ getType(): String
+ getValue(): double
+ getDate(): Date
}
' 关联关系
MainUI --> DeveloperUI : "跳转"
DeveloperUI --> AlgorithmController : "调用"
AlgorithmController --> DateBase : "查询"
AlgorithmController ..> DeveloperAnalysisResult : "生成"
DateBase "1" *-- "many" DeveloperData : "包含"
DeveloperData "1" *-- "many" Contribution : "包含"
DeveloperAnalysisResult ..> DeveloperData : "基于"
@enduml

@ -1,94 +0,0 @@
@startuml
skinparam class {
BackgroundColor<<boundary>> LightSkyBlue
BackgroundColor<<control>> LightGreen
BackgroundColor<<entity>> Gold
}
class MainUI <<boundary>> {
- configUI: ConfigUI
+ startPage()
+ showMainInterface()
+ navigateToSystemConfigPage()
}
class ConfigUI <<boundary>> {
- algorithmController: AlgorithmController
- currentConfig: SystemConfig
+ showSystemConfigPage()
+ displayModificationSuccess(message: String)
+ modifyAlgorithmParameters(params: Map<String, Object>)
}
class AlgorithmController <<control>> {
- database: DateBase
+ modifyAlgorithmParameters(params: Map<String, Object>): boolean
+ getCurrentConfig(): SystemConfig
}
class DateBase <<entity>> {
- systemConfig: SystemConfig
- configHistory: List<ConfigHistory>
+ getSystemConfig(): SystemConfig
+ updateSystemConfig(config: SystemConfig): boolean
+ saveConfigHistory(history: ConfigHistory): boolean
}
class SystemConfig <<entity>> {
- configId: String
- version: String
- parameters: Map<String, Object>
- lastModified: Date
- modifiedBy: String
+ getParameter(key: String): Object
+ setParameter(key: String, value: Object): void
+ getAllParameters(): Map<String, Object>
+ validateParameters(): boolean
}
class ConfigHistory <<entity>> {
- historyId: String
- configId: String
- oldValues: Map<String, Object>
- newValues: Map<String, Object>
- modifiedBy: String
- modificationTime: Date
+ getChangeDescription(): String
+ rollback(): SystemConfig
}
class AlgorithmParameter <<entity>> {
- parameterName: String
- parameterType: String
- defaultValue: Object
- minValue: Object
- maxValue: Object
- description: String
+ validateValue(value: Object): boolean
+ getDescription(): String
}
class User <<entity>> {
- userId: String
- username: String
- role: String
- permissions: List<String>
+ getUserId(): String
+ getUsername(): String
+ hasPermission(permission: String): boolean
}
' 关联关系
MainUI --> ConfigUI : "跳转"
ConfigUI --> AlgorithmController : "调用"
AlgorithmController --> DateBase : "更新"
DateBase "1" *-- "1" SystemConfig : "当前配置"
DateBase "1" *-- "many" ConfigHistory : "配置历史"
SystemConfig "1" *-- "many" AlgorithmParameter : "包含参数"
ConfigHistory ..> SystemConfig : "关联"
ConfigHistory ..> User : "记录操作者"
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

@ -0,0 +1,396 @@
# OpenRank 复现项目
这是一个基于 open-digger 和 openrank-neo4j-gds 项目的 OpenRank 算法复现实现,用于开发者贡献度量和开源社区分析。
## 项目概述
OpenRank 是由 X-lab 开发的开源项目价值评估算法,基于 PageRank 改进而来,专门用于评估开源生态中开发者和项目的贡献价值。本项目提供了一个完整的 OpenRank 算法复现实现。
## 特性
- ✅ **完整的 OpenRank 算法实现**:基于原始论文和开源代码的忠实复现
- ✅ **支持多种计算模式**:全域 OpenRank 和项目级 OpenRank
- ✅ **灵活的数据源接口**:支持桩函数模拟和真实数据源
- ✅ **丰富的指标计算**:仓库、用户、社区等多维度分析
- ✅ **高性能图计算**:优化的图数据结构和迭代算法
- ✅ **完善的配置系统**:支持参数调优和环境适配
- ✅ **TypeScript 支持**:完整的类型定义和代码提示
## 安装
```bash
# 克隆项目
git clone <repository-url>
cd openrank
# 安装依赖
npm install
# 构建项目
npm run build
```
## 快速开始
### 基础使用
```typescript
import { OpenRank } from './src';
// 创建 OpenRank 实例
const openrank = new OpenRank('./data');
// 运行 OpenRank 计算
const startDate = new Date('2024-01-01');
const endDate = new Date('2024-12-31');
const results = await openrank.calculate(startDate, endDate);
// 获取 Top 10 仓库 OpenRank
const topRepos = await openrank.getRepoOpenrank({
startYear: 2024,
startMonth: 1,
endYear: 2024,
endMonth: 12,
limit: 10,
order: 'DESC'
});
console.log('Top 10 仓库:', topRepos);
```
### 高级查询
```typescript
import { MetricsCalculator, MockDataSource } from './src';
const dataSource = new MockDataSource('./data');
const calculator = new MetricsCalculator(dataSource);
// 获取分布统计
const distribution = await calculator.getOpenrankDistribution({
startYear: 2024,
startMonth: 1,
endYear: 2024,
endMonth: 12,
});
// 比较不同时期
const comparison = await calculator.compareOpenrank(
{ startYear: 2024, startMonth: 1, endYear: 2024, endMonth: 6 },
{ startYear: 2024, startMonth: 7, endYear: 2024, endMonth: 12 },
'repo'
);
```
## 配置
### 配置文件
`config/openrank.yml` 中配置算法参数:
```yaml
global:
developerRetentionFactor: 0.5 # 开发者继承比例
repositoryRetentionFactor: 0.3 # 仓库继承比例
attenuationFactor: 0.85 # OpenRank 衰减系数
tolerance: 0.01 # 收敛容差
maxIterations: 100 # 最大迭代次数
activityWeights:
issueComment: 0.5252 # Issue 评论权重
openIssue: 2.2235 # 创建 Issue 权重
openPull: 4.0679 # 创建 PR 权重
reviewComment: 0.7427 # 代码评审权重
mergedPull: 2.0339 # 合入 PR 权重
projectActivityWeights:
# 活动类型权重(项目级 OpenRank 用)
open: 2.0
comment: 0.5
review: 1.0
close: 0.3
commit: 1.5
# 反刷与密度抑制(推荐开启):
antiGaming:
enabled: true
commentTransform: sqrt # 对高频评论做亚线性变换,降低刷量影响
commitTransform: sqrt
linearThresholds: # 前 N 条线性累加超过部分按变换sqrt/log
comment: 3
reviewComment: 3
commit: 1
perItemCap: # 每个 Issue/PR 的单项计数上限,防极端
comment: 50
reviewComment: 40
commit: 20
# PR 贡献类型与角色建模
contributionTypeMultipliers:
open: 1.0
comment: 0.9
review: 1.1
close: 1.0
commit: 1.05
reviewerChangeRequestBonus: 1.03 # 存在 change requests 时对评审者的轻量加成
roleBonus: # 角色轻量加成(叠乘后会被 roleClamp 限制)
author: 1.05
reviewer: 1.05
committer: 1.03
commenter: 1.0
roleClamp: # 角色乘子钳制,避免叠乘过大
min: 1.0
max: 1.2
clamp: # 总贡献钳制,相对原始分项总和
min: 0.7
max: 1.6
# 仓库层事件Star/Fork/Release可选接入
repoEventWeights:
enabled: false
star: 0.5
fork: 1.0
release: 1.5
activityRatio: 0.2
reverseRatio: 0.1
```
提示:
- activityDetails.roles 会在活动边上标注作者/评审者/提交者/评论者,便于后续分析与报表。
- 通过 `getGraphSnapshot()` 可以导出包含 activityDetails 的只读快照,用于检查来源与角色细节。
### 环境变量
```bash
# 设置全局收敛容差
export OPENRANK_GLOBAL_TOLERANCE=0.01
# 设置最大迭代次数
export OPENRANK_GLOBAL_MAX_ITERATIONS=100
```
## API 参考
### 核心类
#### OpenRank
主要的 OpenRank 计算接口。
```typescript
class OpenRank {
constructor(dataPath?: string)
// 计算 OpenRank
async calculate(startDate: Date, endDate: Date): Promise<OpenRankResult[]>
// 获取仓库 OpenRank
async getRepoOpenrank(config: QueryConfig): Promise<RepoOpenRankResult[]>
// 获取用户 OpenRank
async getUserOpenrank(config: QueryConfig): Promise<UserOpenRankResult[]>
// 获取社区 OpenRank
async getCommunityOpenrank(config: QueryConfig): Promise<CommunityOpenRankResult[]>
}
```
#### OpenRankCalculator
核心算法实现。
```typescript
class OpenRankCalculator {
constructor(config: OpenRankConfig)
async calculate(
activityData: ActivityData[],
lastMonthOpenRank: Map<string, number>
): Promise<OpenRankResult[]>
getCalculationStatus(): CalculationStatus
getGraphStats(): GraphStats
}
```
#### MetricsCalculator
指标计算器。
```typescript
class MetricsCalculator {
constructor(dataSource: DataSource)
async getRepoOpenrank(config: QueryConfig): Promise<RepoOpenRankResult[]>
async getUserOpenrank(config: QueryConfig): Promise<UserOpenRankResult[]>
async getCommunityOpenrank(config: QueryConfig): Promise<CommunityOpenRankResult[]>
async getOpenrankDistribution(config: QueryConfig): Promise<DistributionStats>
async compareOpenrank(config1: QueryConfig, config2: QueryConfig): Promise<ComparisonResult>
}
```
### 查询配置
```typescript
interface QueryConfig {
startYear: number;
startMonth: number;
endYear: number;
endMonth: number;
order?: 'DESC' | 'ASC';
limit: number;
precision: number;
options?: Record<string, any>;
}
```
## 算法原理
### 全域 OpenRank
全域 OpenRank 基于全局协作网络计算,考虑以下因素:
1. **网络构建**:以开发者和仓库为节点,活动关系为边
2. **权重计算**:使用活动度指标作为边权重
3. **历史继承**:节点部分继承上个月的 OpenRank 值
4. **迭代收敛**:使用改进的 PageRank 算法计算
### 项目级 OpenRank
项目级 OpenRank 在项目内部计算,包含更多节点类型:
1. **节点类型**开发者、仓库、Issue、Pull Request
2. **复杂网络**:多种关系类型和权重配置
3. **精细参数**:不同节点类型的不同继承因子
### 关键参数
- **继承因子**:控制历史价值的保留程度
- **衰减因子**:控制不活跃节点的价值衰减
- **活动权重**:不同活动类型的重要性权重
- **收敛容差**:算法收敛的精度要求
## 运行示例
```bash
# 运行基础示例
npm run dev
# 运行测试
npm test
# 检查代码质量
npm run lint
```
## A/B 评估仓库事件影响Repo Events
为评估是否引入仓库层事件Star/Fork/Release 等)对项目级 OpenRank 的影响,本项目提供了 A/B 对比脚本:
- 脚本:`scripts/ab_evaluate_repo_events.ts`
- 运行方式:`npm run ab:repo-events`
- 环境变量(可选):
- `GITHUB_TOKEN`GitHub 访问令牌,避免触发未认证的频率限制
- `OR_AB_OWNER`/`OR_AB_REPO`:目标仓库,默认 `FISCO-BCOS/FISCO-BCOS`
- `OR_AB_MONTHS`:时间窗口(月),默认 `3`
脚本将输出:
- A不启用 repo events与 B启用 repo events之间的用户 OpenRank 相关性(皮尔逊)
- 贡献构成按事件来源的占比对比collaboration vs repo_event
提示:若遇到 GitHub API 频率限制,请设置 `GITHUB_TOKEN`,或将 `OR_AB_MONTHS` 调小(如设为 1
## 项目结构
```
openrank/
├── src/
│ ├── types/ # TypeScript 类型定义
│ ├── config/ # 配置管理
│ ├── utils/ # 工具函数
│ ├── data/ # 数据层(桩函数)
│ ├── algorithm/ # 核心算法
│ ├── metrics/ # 指标计算
│ └── index.ts # 主入口
├── config/ # 配置文件
├── examples/ # 使用示例
├── data/ # 数据存储目录
└── docs/ # 文档
```
## 开发指南
### 添加新的数据源
1. 实现 `DataSource` 接口
2. 在 `src/data/` 目录下创建新的数据源类
3. 更新导出文件
```typescript
export class CustomDataSource implements DataSource {
async loadActivityData(startDate: Date, endDate: Date): Promise<ActivityData[]> {
// 实现数据加载逻辑
}
// 实现其他必需方法...
}
```
### 自定义算法参数
1. 修改 `config/openrank.yml` 配置文件
2. 或使用环境变量覆盖特定参数
3. 或在代码中动态设置配置
```typescript
import { setConfig } from './src/config';
setConfig({
global: {
tolerance: 0.001,
maxIterations: 200,
}
});
```
## 测试
```bash
# 运行单元测试
npm test
# 运行覆盖率测试
npm run test:coverage
# 运行集成测试
npm run test:integration
```
## 贡献
欢迎提交 Issue 和 Pull Request
1. Fork 本仓库
2. 创建特性分支 (`git checkout -b feature/amazing-feature`)
3. 提交更改 (`git commit -m 'Add some amazing feature'`)
4. 推送到分支 (`git push origin feature/amazing-feature`)
5. 开启 Pull Request
## 许可证
本项目采用 Apache-2.0 许可证,详见 [LICENSE](LICENSE) 文件。
## 参考资料
- [open-digger](https://github.com/X-lab2017/open-digger) - 原始项目和数据平台
- [openrank-neo4j-gds](https://github.com/X-lab2017/openrank-neo4j-gds) - Neo4j 插件实现
- [OpenRank 算法论文](https://blog.frankzhao.cn/openrank_in_project/) - 算法设计思路
- [X-lab 开放实验室](https://x-lab.info) - 项目发起方
## 联系方式
如有问题或建议,请通过以下方式联系:
- 提交 GitHub Issue
- 发送邮件至 [contact@example.com]
- 加入讨论群组 [链接]

@ -1,22 +0,0 @@
[paths]
source =
pylint
[report]
include =
pylint/*
omit =
*/test/*
exclude_also =
# Debug-only code
def __repr__
# Type checking code not executed during pytest runs
if TYPE_CHECKING:
@overload
# Abstract methods are not executed during pytest runs
raise NotImplementedError()
# Fallback cases which should never be executed
raise AssertionError

@ -1 +0,0 @@
3f2842400795ae1aaffc4ae6c35c4ef26857c239

@ -1,7 +0,0 @@
* text=auto
tests/**/functional/** -text
tests/input/** -text
tests/**/data/** -text
tests/regrtest_data/** -text
doc/data/messages/u/unexpected-line-ending-format/bad.py -text
doc/data/messages/m/mixed-line-endings/bad.py -text

@ -1,35 +0,0 @@
# Lines starting with '#' are comments.
# Each line is a file pattern followed by one or more owners.
# These owners will be the default owners for everything in the repo.
# Right now there is not default owner to avoid spam
# * @pierre-sassoulas @DanielNoord @cdce8p @jacobtylerwalls @hippo91
# Order is important. The last matching pattern has the most precedence.
### Core components
# internal message handling
pylint/message/* @pierre-sassoulas
tests/message/* @pierre-sassoulas
# typing
pylint/typing.py @DanielNoord
# multiprocessing (doublethefish is not yet a contributor with write access)
# pylint/lint/parallel.py @doublethefish
# tests/test_check_parallel.py @doublethefish
### Pyreverse
pylint/pyreverse/* @DudeNr33
tests/pyreverse/* @DudeNr33
### Extensions
# CodeStyle
pylint/extensions/code_style.* @cdce8p
tests/functional/ext/code_style/* @cdce8p
# Typing
pylint/extensions/typing.* @cdce8p
tests/functional/ext/typing/* @cdce8p

@ -1,2 +0,0 @@
Please read the
[contribute doc](https://pylint.readthedocs.io/en/latest/development_guide/contributor_guide/contribute.html).

@ -1,3 +0,0 @@
# These are supported funding model platforms
tidelift: "pypi/pylint"
github: [cdce8p, DanielNoord, jacobtylerwalls,Pierre-Sassoulas]

@ -1,108 +0,0 @@
name: 🐛 Bug report
description: Report a bug in pylint
labels: ["Needs triage :inbox_tray:"]
body:
- type: markdown
attributes:
value: |
**Thank you for wanting to report a bug in pylint!**
⚠ Please make sure that this [issue wasn't already requested][issue search], or already implemented in the main branch.
[issue search]: https://github.com/pylint-dev/pylint/issues?q=is%3Aissue+is%3Aopen+
- type: textarea
id: what-happened
attributes:
label: Bug description
description:
What is the bug about? Please provide the code that is causing the issue, and
configurations used if required
placeholder: |
# Please disable message unrelated to the bug
# pylint: disable=missing-docstring,
<a> = b + 1
render: python
validations:
required: true
- type: textarea
id: configuration
attributes:
label: Configuration
description:
Please provide the part of the configuration that is causing the bug if required
(Leave this part blank if the configuration is not relevant)
placeholder: |
# Leave this blank if the configuration is not relevant!
[MAIN]
load-plugins=
pylint.extensions.code_style
[MESSAGE CONTROL]
enable=
useless-suppression
# ...
render: ini
- type: textarea
id: cmd-used
attributes:
label: Command used
description: What was the command used to invoke pylint?
placeholder: |
pylint a.py
render: shell
validations:
required: true
- type: textarea
id: current-behavior
attributes:
label: Pylint output
description: What is the current pylint output?
placeholder: |
************* Module a
a.py:3:1: E0001: invalid syntax (<unknown>, line 1) (syntax-error)
render: python
validations:
required: true
- type: textarea
id: future-behavior
attributes:
label: Expected behavior
description:
What would you expect instead? For example expected output or behavior
validations:
required: true
- type: textarea
id: python-interpreter
attributes:
label: Pylint version
description: >-
Please copy and paste the result of `pylint --version` or specify the range of
versions affected.
placeholder: |
pylint 3.3.0
astroid 3.3.0
Python 3.12.0 (v3.12.0:0fb18b02c8, Oct 2 2023, 09:45:56)
render: shell
validations:
required: true
- type: textarea
attributes:
label: OS / Environment
description: >-
Provide all relevant information below, e.g. OS version, terminal etc.
placeholder: Fedora 33, Cygwin, etc.
- type: textarea
id: additional-deps
attributes:
label: Additional dependencies
description:
If applicable ie, if we can't reproduce without it. Please copy and paste the
result of `pip freeze`.
placeholder: |
pandas==0.23.2
marshmallow==3.10.0
render: python

@ -1,45 +0,0 @@
name: ✨ Feature request
description: Suggest an idea for pylint
labels: ["Needs triage :inbox_tray:"]
body:
- type: markdown
attributes:
value: |
**Thank you for wanting to make a suggestion for pylint!**
⚠ Please make sure that [this feature wasn't already requested][issue search] or already implemented in the main branch.
[issue search]: https://github.com/pylint-dev/pylint/issues?q=is%3Aissue+is%3Aopen+
- type: textarea
id: current-problem
attributes:
label: Current problem
description:
What are you trying to do, that you are unable to achieve with pylint as it
currently stands?
placeholder: >-
I'm trying to do X and I'm missing feature Y for this to be easily achievable.
validations:
required: true
- type: textarea
id: proposed-solution
attributes:
label: Desired solution
description: A clear and concise description of what you want to happen.
placeholder: >-
When I do X, I want to achieve Y in a situation when Z.
validations:
required: true
- type: textarea
attributes:
label: Additional context
description: >
Add any other context, links, etc. about the feature here. Describe how the
feature would be used, why it is needed and what it would solve.
**HINT:** You can paste https://gist.github.com links for larger files.
placeholder: >-
I asked on https://stackoverflow.com/... and the community advised me to do X, Y
and Z.

@ -1,49 +0,0 @@
name: 🤔 Support question
description: Questions about pylint that are not covered in the documentation
labels: ["Needs triage :inbox_tray:", "Question", "Documentation :green_book:"]
body:
- type: markdown
attributes:
value: >
**Thank you for wanting to report a problem with pylint documentation!**
Please fill out your suggestions below. If the problem seems straightforward,
feel free to go ahead and submit a pull request instead!
⚠ Verify first that your issue is not [already reported on GitHub][issue
search].
💬 If you are seeking community support, please consider [starting a discussion
on Discord][Discussions].
[issue search]:
https://github.com/pylint-dev/pylint/issues?q=is%3Aissue+is%3Aopen+
[Discussions]: https://discord.com/invite/Egy6P8AMB5
- type: textarea
id: question
attributes:
label: Question
validations:
required: true
- type: textarea
id: documentation
attributes:
label: Documentation for future user
description:
Where did you expect this information to be? What do we need to add or what do
we need to reorganize?
validations:
required: true
- type: textarea
attributes:
label: Additional context
description: >
Add any other context, links, etc. about the question here.
placeholder: >-
I asked on https://stackoverflow.com/... and the community advised me to do X, Y
and Z.

@ -1,5 +0,0 @@
blank_issues_enabled: true
contact_links:
- name: 💬 Discord
url: https://discord.com/invite/Egy6P8AMB5
about: Astroid and pylint informal dev discussion

@ -1,41 +0,0 @@
<!--
Thank you for submitting a PR to pylint!
To ease the process of reviewing your PR, do make sure to complete the following boxes.
- [ ] Document your change, if it is a non-trivial one.
- A maintainer might label the issue ``skip-news`` if the change does not need to be in the changelog.
- Otherwise, create a news fragment with ``towncrier create <IssueNumber>.<type>`` which will be
included in the changelog. ``<type>`` can be one of the types defined in `./towncrier.toml`.
If necessary you can write details or offer examples on how the new change is supposed to work.
- Generating the doc is done with ``tox -e docs``
- [ ] Relate your change to an issue in the tracker if such an issue exists (Refs #1234, Closes #1234)
- [ ] Write comprehensive commit messages and/or a good description of what the PR does.
- [ ] Keep the change small, separate the consensual changes from the opinionated one.
Don't hesitate to open multiple PRs if the change requires it. If your review is so
big it requires to actually plan and allocate time to review, it's more likely
that it's going to go stale.
- [ ] If you used multiple emails or multiple names when contributing, add your mails
and preferred name in ``script/.contributors_aliases.json``
-->
## Type of Changes
<!-- Leave the corresponding lines for the applicable type of change: -->
| | Type |
| --- | ---------------------- |
| ✓ | :bug: Bug fix |
| ✓ | :sparkles: New feature |
| ✓ | :hammer: Refactoring |
| ✓ | :scroll: Docs |
## Description
<!-- If this PR references an issue without fixing it: -->
Refs #XXXX
<!-- If this PR fixes an issue, use the following to automatically close when we merge: -->
Closes #XXXX

@ -1 +0,0 @@
Coordinated Disclosure Plan: https://tidelift.com/security

@ -1,255 +0,0 @@
# Pylint Development Instructions
Always follow these instructions first and fallback to additional search and context
gathering only if the information in these instructions is incomplete or found to be in
error.
## Issue Label Guidelines
Before attempting to fix any issue, check the GitHub issue labels using the GitHub API:
- If an issue is labeled with "Astroid", "Needs astroid update", "Needs astroid
constraint", or "Needs astroid Brain 🧠", **ONLY** create regression tests
- Do **NOT** attempt to fix astroid-related issues as you cannot modify astroid from
this repository
- For astroid-related issues, focus on creating comprehensive regression tests that
reproduce the problem
- All other issues can be fixed normally following the standard development workflow
## Development Environment Setup
### Basic Installation
Clone and set up pylint development environment:
- `git clone https://github.com/pylint-dev/pylint` -- clone repository
- `cd pylint` -- enter directory
- `python3 -m venv venv` -- create virtual environment
- `source venv/bin/activate` -- activate virtual environment (Linux/Mac)
- `pip install -r requirements_test_min.txt` -- install test dependencies (~30 seconds)
- `pip install -e .` -- install pylint in editable mode (~30-60 seconds)
### Optional Setup Steps
- `pre-commit install` -- enable pre-commit hooks for autoformatting
- `pip install pre-commit` -- install pre-commit separately if needed
### Astroid Development (if needed)
If working on astroid changes:
- `git clone https://github.com/pylint-dev/astroid.git` -- clone astroid
- `pip install -e astroid/` -- install astroid in editable mode
- `cd astroid/ && git switch my-astroid-dev-branch` -- switch to development branch
## Running Tests
### Core Test Commands
- `pytest tests/test_functional.py -k test_functional` -- run functional tests (~60
seconds, NEVER CANCEL, set timeout to 120+ seconds)
- `pytest tests/` -- run all tests (several minutes, NEVER CANCEL, set timeout to 300+
seconds)
- `python3 -m pytest` -- run tests with local python
- `pytest tests/test_check_parallel.py -v` -- quick test file (~2 seconds)
### Specific Test Types
- **Functional tests:**
`pytest "tests/test_functional.py::test_functional[missing_kwoa_py3]"` -- single
functional test (~1 second)
- **Unit tests:** Located in `/tests/` directory, test specific pylint functionality
- **Configuration tests:** In `/tests/config/functional/` for testing configuration
loading
- **Primer tests:** `pytest -m primer_stdlib --primer-stdlib` -- test on stdlib for
crashes
### Test with Coverage
- `pytest tests/message/ --cov=pylint.message` -- run with coverage
- `coverage html` -- generate HTML coverage report
### Tox Usage (Optional)
- `python -m tox` -- run all tox environments
- `python -m tox -epy313` -- run Python 3.13 suite only
- `python -m tox -epylint` -- run pylint on pylint's codebase
- `python -m tox -eformatting` -- run formatting checks
- `python -m tox --recreate` -- recreate environments (recommended)
- `python -m tox -e py310 -- -k test_functional` -- run specific tests in tox
## Documentation
### Building Documentation
- `make -C doc/ install-dependencies` -- install doc dependencies (~10 seconds)
- `make -C doc/ html` -- build documentation (~3 minutes, NEVER CANCEL, set timeout to
300+ seconds)
- `make -C doc/ clean` -- clean build files when starting from scratch
- `tox -e docs` -- alternative way to build docs
**Network dependency:** Documentation build requires internet access to fetch external
inventories.
## Validation and Quality Checks
### Running Pylint on Code
- `pylint --help` -- verify pylint installation works
- `pylint --disable=all --enable=E,F pylint/` -- run pylint on itself for errors only
(~20 seconds)
- `pylint --rcfile=pylintrc --fail-on=I path/to/your/changes.py` -- standard pylint run
- `pylint --disable=all --enable=E,F,W path/to/your/changes.py` -- focus on errors and
warnings
### Pre-commit and Formatting
- `pre-commit run --all-files` -- run all formatting checks (requires network for
initial setup)
- **Network dependency:** pre-commit may fail in isolated environments due to hook
downloads
### Validation Test Scenarios
Always test your changes with these validation scenarios:
- `echo "def badFunction(): pass" > /tmp/test_sample.py && pylint --enable=C0103 /tmp/test_sample.py`
-- should find naming issues
- `pylint --help` and `pylint --list-msgs | head -10` -- verify CLI functionality
- `pylint --help-msg=C0103` -- should show invalid-name help
- `pylint --rcfile=pylintrc --fail-on=I pylint/__init__.py` -- should get 10.00/10
rating
## Writing Tests
### Functional Tests
Located in `/tests/functional/`, consists of `.py` test files with corresponding `.txt`
expected output files:
- Annotate lines where messages are expected:
`a, b, c = 1 # [unbalanced-tuple-unpacking]`
- Multiple messages on same line:
`a, b, c = 1.test # [unbalanced-tuple-unpacking, no-member]`
- Use offset syntax for special cases: `# +1: [singleton-comparison]`
- **Run and update:**
`python tests/test_functional.py --update-functional-output -k "test_functional[test_name]"`
### Test File Organization
- **New checkers:** Create `new_checker_message.py` in `/tests/functional/n/`
- **Extensions:** Place in `/tests/functional/ext/extension_name/`
- **Regression tests:** Place in `/tests/r/regression/` with `regression_` prefix
- **Configuration tests:** Place in `/tests/config/functional/`
### Configuration Test Files
Create `.result.json` files with configuration differences from standard config:
```json
{
"functional_append": {
"disable": [["a-message-to-be-added"]]
},
"jobs": 10
}
```
## Codebase Structure
```
pylint/ # Main package
├── checkers/ # All pylint checkers (rules implementation)
├── config/ # Configuration handling and parsing
├── message/ # Message system and formatting
├── reporters/ # Output formatters (text, json, etc.)
├── testutils/ # Testing utilities and helpers
└── extensions/ # Optional extensions and plugins
tests/ # Test suite
├── functional/ # Functional test files (.py + .txt expected output)
├── config/functional/ # Configuration functional tests
├── r/regression/ # Regression tests
├── test_*.py # Unit tests
└── regrtest_data/ # Test data files
doc/ # Documentation
├── user_guide/ # User documentation
├── development_guide/ # Developer and contributor documentation
│ ├── contributor_guide/ # Setup, testing, contribution guidelines
│ ├── technical_reference/ # Technical implementation details
│ └── how_tos/ # Guides for custom checkers, plugins
└── additional_tools/ # Tools documentation
script/ # Development utility scripts
```
### Key Files
- `pyproject.toml` -- Main configuration (dependencies, build, tools)
- `tox.ini` -- Multi-environment testing configuration
- `.pre-commit-config.yaml` -- Code quality checks configuration
- `pylintrc` -- Pylint's own configuration
- `requirements_test_min.txt` -- Minimal test dependencies
- `.gitignore` do not add the 'venv' inside the .gitignore, don't commit the venv in the
first place (humans add it to their global gitignore)
## Creating New Checkers
### Getting Started
- `python script/get_unused_message_id_category.py` -- get next available message ID
- Study existing checkers in `pylint/checkers/` for patterns
- Read technical reference documentation in `doc/development_guide/technical_reference/`
- Use `astroid.extract_node` for AST manipulation
### Workflow
1. Create checker class in appropriate `pylint/checkers/` file
2. Add functional tests in `tests/functional/`
3. Search existing code for warning message to find where logic exists
4. Test with sample code to ensure functionality works
## Pull Request Guidelines
### Before Submitting
- Use Python 3.8+ for development (required for latest AST parser and pre-commit hooks)
- Write comprehensive commit messages relating to tracker issues
- Keep changes small and separate consensual from opinionated changes
- Add news fragment: `towncrier create <IssueNumber>.<type>`
- Always launch `pre-commit run -a` before committing
### Documentation Changes
- Document non-trivial changes
- Generate docs with `tox -e docs`
- Maintainers may label issues `skip-news` if no changelog needed
### Contribution Credits
- Add emails/names to `script/.contributors_aliases.json` if using multiple identities
## Critical Timing Information
- **NEVER CANCEL:** All operations that show "NEVER CANCEL" may take significant time
- **Full test suite:** 60+ seconds (set timeout to 120+ seconds)
- **Documentation build:** 180 seconds (set timeout to 300+ seconds)
- **Functional tests:** 60 seconds (set timeout to 120+ seconds)
- **Pylint self-check:** 20 seconds (set timeout to 60+ seconds)
- **Individual test files:** 1-15 seconds
- **Installation steps:** 30-60 seconds each
## Environment Limitations and Workarounds
- **Network connectivity required:** Documentation build and pre-commit setup require
internet access
- **Tox failures:** In isolated environments, use direct pytest and pip commands instead
of tox
- **Import errors in self-check:** Some import errors when running pylint on itself are
expected (git dependencies not installed)
- **Build environments:** Use direct pip/pytest commands when tox environments fail to
build
Always validate your changes by running pylint on sample code to ensure functionality
works correctly.

@ -1,21 +0,0 @@
version: 2
updates:
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
labels:
- "dependency"
- "Skip news :mute:"
open-pull-requests-limit: 10
rebase-strategy: "disabled"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
labels:
- "dependency"
- "Skip news :mute:"
open-pull-requests-limit: 10
rebase-strategy: "disabled"

@ -1,40 +0,0 @@
name: Backport
on:
pull_request_target:
types:
- closed
- labeled
permissions:
contents: read
jobs:
backport:
name: Backport
runs-on: ubuntu-latest
environment:
name: Backport
# Only react to merged PRs for security reasons.
# See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target.
if: >
github.event.pull_request.merged && (
github.event.action == 'closed'
|| (
github.event.action == 'labeled'
&& contains(github.event.label.name, 'backport')
)
)
steps:
- uses: actions/create-github-app-token@67018539274d69449ef7c02e8e71183d1719ab42 # v2.1.4
id: app-token
with:
app-id: ${{ vars.BACKPORT_APP_ID }}
private-key: ${{ secrets.PRIVATE_KEY }}
permission-contents: write # push branch to Github
permission-pull-requests: write # create PR / add comment for manual backport
permission-workflows: write # modify files in .github/workflows
- uses: pylint-dev/backport@94367840595495e101f9a31415897c05da1f08d9 # v2.1.1
with:
github_token: ${{ steps.app-token.outputs.token }}
user_name: ${{ vars.BACKPORT_USER_NAME }}
user_email: ${{ vars.BACKPORT_USER_EMAIL }}

@ -1,65 +0,0 @@
name: changelog
on:
pull_request:
types: [opened, synchronize, labeled, unlabeled, reopened]
branches-ignore:
- "maintenance/**"
env:
CACHE_VERSION: 1
KEY_PREFIX: base-venv
DEFAULT_PYTHON: "3.13"
permissions:
contents: read
jobs:
check-changelog:
if: contains(github.event.pull_request.labels.*.name, 'skip news :mute:') != true
name: Changelog Entry Check
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Check out code from GitHub
uses: actions/checkout@v5.0.0
with:
# `towncrier check` runs `git diff --name-only origin/main...`, which
# needs a non-shallow clone.
fetch-depth: 0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v6.0.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
- name: Generate partial Python venv restore key
id: generate-python-key
run: >-
echo "key=${{ env.KEY_PREFIX }}-${{ env.CACHE_VERSION }}-${{
hashFiles('pyproject.toml', 'requirements_test.txt',
'requirements_test_min.txt', 'requirements_test_pre_commit.txt') }}" >>
$GITHUB_OUTPUT
- name: Restore Python virtual environment
id: cache-venv
uses: actions/cache@v4.3.0
with:
path: venv
key: >-
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
steps.generate-python-key.outputs.key }}
- name: Create Python virtual environment
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
python -m venv venv
. venv/bin/activate
python -m pip install --upgrade pip
pip install --upgrade --requirement requirements_test.txt --requirement doc/requirements.txt
- name: Emit warning if news fragment is missing
env:
BASE_BRANCH: ${{ github.base_ref }}
run: |
# Fetch the pull request' base branch so towncrier will be able to
# compare the current branch with the base branch.
git fetch --no-tags origin +refs/heads/${BASE_BRANCH}:refs/remotes/origin/${BASE_BRANCH}
. venv/bin/activate
towncrier check --compare-with origin/${{ github.base_ref }}

@ -1,160 +0,0 @@
name: Checks
on:
push:
branches:
- main
- "maintenance/**"
pull_request:
branches:
- main
- "maintenance/**"
workflow_dispatch:
env:
CACHE_VERSION: 3
KEY_PREFIX: base-venv
DEFAULT_PYTHON: "3.13"
PRE_COMMIT_CACHE: ~/.cache/pre-commit
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
prepare-base:
name: Prepare base dependencies
runs-on: ubuntu-latest
timeout-minutes: 10
outputs:
python-key: ${{ steps.generate-python-key.outputs.key }}
pre-commit-key: ${{ steps.generate-pre-commit-key.outputs.key }}
steps:
- &checkout
name: Check out code from GitHub
uses: actions/checkout@v5.0.0
- &setup-python
name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v6.0.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
- name: Generate partial Python venv restore key
id: generate-python-key
run: >-
echo "key=${{ env.KEY_PREFIX }}-${{ env.CACHE_VERSION }}-${{
hashFiles('pyproject.toml', 'requirements_test.txt',
'requirements_test_min.txt', 'requirements_test_pre_commit.txt') }}" >>
$GITHUB_OUTPUT
- name: Restore Python virtual environment
id: cache-venv
uses: actions/cache@v4.3.0
with:
path: venv
key: >-
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
steps.generate-python-key.outputs.key }}
- name: Create Python virtual environment
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
python -m venv venv
. venv/bin/activate
python -m pip install --upgrade pip
pip install --upgrade --requirement requirements_test.txt --requirement doc/requirements.txt
pip install pre-commit
- name: Generate pre-commit restore key
id: generate-pre-commit-key
run: >-
echo "key=pre-commit-${{ env.CACHE_VERSION }}-${{
hashFiles('.pre-commit-config.yaml') }}" >> $GITHUB_OUTPUT
- name: Restore pre-commit environment
id: cache-precommit
uses: actions/cache@v4.3.0
with:
path: ${{ env.PRE_COMMIT_CACHE }}
key: >-
${{ runner.os }}-${{ steps.generate-pre-commit-key.outputs.key }}
- name: Install pre-commit dependencies
if: steps.cache-precommit.outputs.cache-hit != 'true'
run: |
. venv/bin/activate
pre-commit install --install-hooks
pylint:
name: pylint
runs-on: ubuntu-latest
timeout-minutes: 10
needs: [prepare-base]
steps:
- *checkout
- *setup-python
- &cache-restore-python
name: Restore Python virtual environment
id: cache-venv
uses: actions/cache/restore@v4.3.0
with:
path: venv
fail-on-cache-miss: true
key:
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
needs.prepare-base.outputs.python-key }}
- name: Restore pre-commit environment
id: cache-precommit
uses: actions/cache/restore@v4.3.0
with:
path: ${{ env.PRE_COMMIT_CACHE }}
fail-on-cache-miss: true
key: ${{ runner.os }}-${{ needs.prepare-base.outputs.pre-commit-key }}
- name: Install enchant and aspell
run: |
sudo apt-get update
sudo apt-get install enchant-2 aspell-en
- name: Run pylint checks
run: |
. venv/bin/activate
pip install . --no-deps
pip list | grep 'astroid\|pylint'
pre-commit run --hook-stage manual pylint-with-spelling --all-files
spelling:
name: spelling tests
runs-on: ubuntu-latest
timeout-minutes: 5
needs: [prepare-base]
steps:
- *checkout
- *setup-python
- *cache-restore-python
- name: Run spelling checks
run: |
. venv/bin/activate
pip install . --no-deps
pytest tests/ -k unittest_spelling --benchmark-disable
documentation:
name: documentation
runs-on: ubuntu-latest
timeout-minutes: 20
needs: [prepare-base]
steps:
- *checkout
- *setup-python
- *cache-restore-python
- name: Run checks on documentation code examples
run: |
. venv/bin/activate
tox -e test_doc
- name: Check documentation build and links
run: |
. venv/bin/activate
tox -e docs || {
echo "git diff:" ; \
git diff ; \
echo "End of 'git diff'" ; \
echo "Make sure that 'tox -e docs' succeed without any modifications locally." ; \
exit 1; \
}

@ -1,80 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [main]
pull_request:
# The branches below must be a subset of the branches above
branches: [main]
schedule:
- cron: "44 16 * * 4"
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
analyze:
if:
${{ github.repository_owner == 'pylint-dev' || github.event_name != 'schedule' }}
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: ["python"]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v5.0.0
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v4
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4

@ -1,95 +0,0 @@
name: Primer
on:
push:
branches:
- main
pull_request:
paths:
- "pylint/**"
- "tests/primer/**"
- "requirements*"
- ".github/workflows/primer-test.yaml"
branches:
- main
env:
CACHE_VERSION: 4
KEY_PREFIX: venv
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
prepare-tests-linux:
name: prepare / ${{ matrix.python-version }} / Linux
runs-on: ubuntu-latest
timeout-minutes: 5
strategy:
matrix:
python-version: &matrix-python-version ["3.10", "3.11", "3.12", "3.13", "3.14"]
outputs:
python-key: ${{ steps.generate-python-key.outputs.key }}
steps:
- &checkout
name: Check out code from GitHub
uses: actions/checkout@v5.0.0
- &setup-python
name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v6.0.0
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
check-latest: true
- name: Generate partial Python venv restore key
id: generate-python-key
run: >-
echo "key=${{ env.KEY_PREFIX }}-${{ env.CACHE_VERSION }}-${{
hashFiles('pyproject.toml', 'requirements_test.txt',
'requirements_test_min.txt', 'requirements_test_pre_commit.txt') }}" >>
$GITHUB_OUTPUT
- name: Restore Python virtual environment
id: cache-venv
uses: actions/cache@v4.3.0
with:
path: venv
key: >-
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
steps.generate-python-key.outputs.key }}
- name: Create Python virtual environment
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
python -m venv venv
. venv/bin/activate
python -m pip install --upgrade pip
pip install --upgrade --requirement requirements_test.txt
pytest-primer-stdlib:
name: run on stdlib / ${{ matrix.python-version }} / Linux
runs-on: ubuntu-latest
timeout-minutes: 10
needs: prepare-tests-linux
strategy:
matrix:
python-version: *matrix-python-version
steps:
- *checkout
- *setup-python
- name: Restore Python virtual environment
id: cache-venv
uses: actions/cache/restore@v4.3.0
with:
path: venv
fail-on-cache-miss: true
key:
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
needs.prepare-tests-linux.outputs.python-key }}
- name: Run pytest
run: |
. venv/bin/activate
pip install . --no-deps
pytest -m primer_stdlib --primer-stdlib -n auto -vv --benchmark-disable

@ -1,125 +0,0 @@
# Most of this is inspired by the mypy primer
# See: https://github.com/hauntsaninja/mypy_primer
# This is the primer job that creates the comment on the PR
# It needs to trigger on workflow_run instead of pull_request
# as we need repository wide access to create a comment
name: Primer / Comment
on:
workflow_run:
workflows: [Primer / Run]
types:
- completed
env:
# This needs to be the SAME as in the Main and PR job
CACHE_VERSION: 4
KEY_PREFIX: venv-primer
# If you change this, also change PRIMER_CURRENT_INTERPRETER in
# tests/testutils/_primer/test_primer.py
DEFAULT_PYTHON: "3.13"
permissions:
contents: read
pull-requests: write
jobs:
primer-comment:
# Skip job if the workflow failed
if: ${{ github.event.workflow_run.conclusion == 'success' }}
name: Run
runs-on: ubuntu-latest
steps:
- name: Check out code from GitHub
uses: actions/checkout@v5.0.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v6.0.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
# Restore cached Python environment
- name: Restore Python virtual environment
id: cache-venv
uses: actions/cache@v4.3.0
with:
path: venv
key:
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
env.KEY_PREFIX }}-${{ env.CACHE_VERSION }}-${{ hashFiles('pyproject.toml',
'requirements_test.txt', 'requirements_test_min.txt',
'requirements_test_pre_commit.txt') }}
- name: Download outputs
uses: actions/github-script@v8.0.0
with:
script: |
// Download workflow pylint output
const fs = require('fs');
const artifacts_workflow = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{ github.event.workflow_run.id }},
});
// Get 'main' and 'PR' outputs and PR number
const artifacts = artifacts_workflow.data.artifacts.filter((artifact) =>
artifact.name.startsWith(`primer_output_main_${process.env.DEFAULT_PYTHON}`)
|| artifact.name.startsWith(`primer_output_pr_${process.env.DEFAULT_PYTHON}`)
|| artifact.name === 'pr_number'
);
for (const artifact of artifacts) {
const downloaded = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: artifact.id,
archive_format: "zip",
});
fs.writeFileSync(`${artifact.name}.zip`, Buffer.from(downloaded.data));
}
- name: Unzip outputs
run: |
unzip primer_output_main_${{ env.DEFAULT_PYTHON }}_batch0.zip
unzip primer_output_main_${{ env.DEFAULT_PYTHON }}_batch1.zip
unzip primer_output_main_${{ env.DEFAULT_PYTHON }}_batch2.zip
unzip primer_output_main_${{ env.DEFAULT_PYTHON }}_batch3.zip
unzip primer_output_pr_${{ env.DEFAULT_PYTHON }}_batch0.zip
unzip primer_output_pr_${{ env.DEFAULT_PYTHON }}_batch1.zip
unzip primer_output_pr_${{ env.DEFAULT_PYTHON }}_batch2.zip
unzip primer_output_pr_${{ env.DEFAULT_PYTHON }}_batch3.zip
unzip pr_number.zip
- name: Compare outputs
run: |
. venv/bin/activate
python tests/primer/__main__.py compare \
--commit=${{ github.event.workflow_run.head_sha }} \
--base-file=output_${{ env.DEFAULT_PYTHON }}_main_BATCHIDX.txt \
--new-file=output_${{ env.DEFAULT_PYTHON }}_pr_BATCHIDX.txt \
--batches=4
- name: Post comment
id: post-comment
uses: actions/github-script@v8.0.0
with:
script: |
const fs = require('fs')
const comment = fs.readFileSync('tests/.pylint_primer_tests/comment.txt', { encoding: 'utf8' })
console.log("Comment to post:")
console.log(comment)
const prNumber = parseInt(fs.readFileSync("pr_number.txt", { encoding: "utf8" }))
await github.rest.issues.createComment({
issue_number: prNumber,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
})
return prNumber
- name: Hide old comments
# Taken from mypy primer
uses: kanga333/comment-hider@c12bb20b48aeb8fc098e35967de8d4f8018fffdf # v0.4.0
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
leave_visible: 1
issue_number: ${{ steps.post-comment.outputs.result }}

@ -1,132 +0,0 @@
# Most of this is inspired by the mypy primer
# See: https://github.com/hauntsaninja/mypy_primer
# This is the primer job that runs on the default 'main' branch
# It is also responsible for caching the packages to prime on
name: Primer / Main
on:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
# This needs to be the SAME as in the PR and comment job
CACHE_VERSION: 4
KEY_PREFIX: venv-primer
permissions:
contents: read
jobs:
run-primer:
name: Run / ${{ matrix.python-version }} / batch index ${{ matrix.batchIdx }}
runs-on: ubuntu-latest
timeout-minutes: 45
strategy:
matrix:
python-version: ["3.10", "3.13"]
batches: [4]
batchIdx: [0, 1, 2, 3]
steps:
- name: Check out code from GitHub
uses: actions/checkout@v5.0.0
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v6.0.0
with:
python-version: ${{ matrix.python-version }}
check-latest: true
# Create a re-usable virtual environment
- name: Restore Python virtual environment cache
id: cache-venv
uses: actions/cache/restore@v4.3.0
with:
path: venv
key:
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
env.KEY_PREFIX }}-${{ env.CACHE_VERSION }}-${{ hashFiles('pyproject.toml',
'requirements_test.txt', 'requirements_test_min.txt',
'requirements_test_pre_commit.txt') }}
- name: Create Python virtual environment
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
python -m venv venv
. venv/bin/activate
python -m pip install --upgrade pip
pip install --upgrade --requirement requirements_test.txt
# Save cached Python environment (explicit because cancel-in-progress: true)
- name: Save Python virtual environment to cache
if: steps.cache-venv.outputs.cache-hit != 'true'
uses: actions/cache/save@v4.3.0
with:
path: venv
key:
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
env.KEY_PREFIX }}-${{ env.CACHE_VERSION }}-${{ hashFiles('pyproject.toml',
'requirements_test.txt', 'requirements_test_min.txt',
'requirements_test_pre_commit.txt') }}
# Cache primer packages
- name: Get commit string
id: commitstring
run: |
. venv/bin/activate
python tests/primer/__main__.py prepare --make-commit-string
output=$(python tests/primer/__main__.py prepare --read-commit-string)
echo "commitstring=$output" >> $GITHUB_OUTPUT
- name: Restore projects cache
id: cache-projects
uses: actions/cache/restore@v4.3.0
with:
path: tests/.pylint_primer_tests/
key: >-
${{ runner.os }}-${{ matrix.python-version }}-${{
steps.commitstring.outputs.commitstring }}-primer
- name: Regenerate cache
if: steps.cache-projects.outputs.cache-hit != 'true'
run: |
. venv/bin/activate
python tests/primer/__main__.py prepare --clone
- name: Save projects cache
if: steps.cache-projects.outputs.cache-hit != 'true'
uses: actions/cache/save@v4.3.0
with:
path: tests/.pylint_primer_tests/
key: >-
${{ runner.os }}-${{ matrix.python-version }}-${{
steps.commitstring.outputs.commitstring }}-primer
- name: Upload commit string
uses: actions/upload-artifact@v4.6.2
if: matrix.batchIdx == 0
with:
name: primer_commitstring_${{ matrix.python-version }}
path:
tests/.pylint_primer_tests/commit_string_${{ matrix.python-version }}.txt
# Run primer
- name: Run pylint primer
run: |
. venv/bin/activate
pip install . --no-deps
python tests/primer/__main__.py run --type=main --batches=${{ matrix.batches }} --batchIdx=${{ matrix.batchIdx }} 2>warnings.txt
- name: Echo warnings
if: success() || failure()
run: |
WARNINGS=$(head -c 65000 < warnings.txt)
if [[ $WARNINGS ]]
then echo "::warning ::$WARNINGS"
fi
- name: Upload output
uses: actions/upload-artifact@v4.6.2
with:
name:
primer_output_main_${{ matrix.python-version }}_batch${{ matrix.batchIdx }}
path: >-
tests/.pylint_primer_tests/output_${{ matrix.python-version }}_main_batch${{
matrix.batchIdx }}.txt

@ -1,225 +0,0 @@
# Most of this is inspired by the mypy primer
# See: https://github.com/hauntsaninja/mypy_primer
# This is the primer job that runs on every PR
name: Primer / Run
on:
pull_request:
paths:
- "pylint/**"
- "tests/primer/**"
- "requirements*"
- ".github/workflows/**"
# We ignore these specific files because they need to be changed
# on 'main' and will always fail the PR run.
- "!.github/workflows/primer_run_main.yaml"
- "!.github/workflows/primer_comment.yaml"
- "!tests/primer/packages_to_prime.json"
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
# This needs to be the SAME as in the Main and comment job
CACHE_VERSION: 4
KEY_PREFIX: venv-primer
permissions:
contents: read
jobs:
run-primer:
name: Run / ${{ matrix.python-version }} / batch index ${{ matrix.batchIdx }}
runs-on: ubuntu-latest
timeout-minutes: 45
strategy:
matrix:
python-version: ["3.10", "3.13"]
batches: [4]
batchIdx: [0, 1, 2, 3]
steps:
- name: Check out code from GitHub
uses: actions/checkout@v5.0.0
with:
fetch-depth: 0
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v6.0.0
with:
python-version: ${{ matrix.python-version }}
check-latest: true
# Restore cached Python environment
- name: Restore Python virtual environment
id: cache-venv
uses: actions/cache/restore@v4.3.0
with:
path: venv
key:
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
env.KEY_PREFIX }}-${{ env.CACHE_VERSION }}-${{ hashFiles('pyproject.toml',
'requirements_test.txt', 'requirements_test_min.txt',
'requirements_test_pre_commit.txt') }}
# Create environment must match step in 'Primer / Main'
- name: Create Python virtual environment
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
python -m venv venv
. venv/bin/activate
python -m pip install --upgrade pip
pip install --upgrade --requirement requirements_test.txt
# Save cached Python environment (explicit because cancel-in-progress: true)
- name: Save Python virtual environment
if: steps.cache-venv.outputs.cache-hit != 'true'
uses: actions/cache/save@v4.3.0
with:
path: venv
key:
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
env.KEY_PREFIX }}-${{ env.CACHE_VERSION }}-${{ hashFiles('pyproject.toml',
'requirements_test.txt', 'requirements_test_min.txt',
'requirements_test_pre_commit.txt') }}
# Cache primer packages
- name: Download last 'main' run info
id: download-main-run
uses: actions/github-script@v8.0.0
env:
COMMIT_STRING_ARTIFACT: primer_commitstring_${{ matrix.python-version }}
OUTPUT_ARTIFACT:
primer_output_main_${{ matrix.python-version }}_batch${{ matrix.batchIdx }}
with:
script: |
const { COMMIT_STRING_ARTIFACT, OUTPUT_ARTIFACT } = process.env
// Download 'main' pylint output
const fs = require('fs');
const runs = await github.rest.actions.listWorkflowRuns({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: ".github/workflows/primer_run_main.yaml",
status: "success"
});
const lastRunMain = runs.data.workflow_runs.reduce(function(prev, current) {
return (prev.run_number > current.run_number) ? prev : current
})
console.log("Last run on main:")
console.log(lastRunMain.html_url)
const artifacts_main = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: lastRunMain.id,
});
// Get commitstring
const [matchArtifactMain] = artifacts_main.data.artifacts.filter((artifact) =>
artifact.name === COMMIT_STRING_ARTIFACT);
const downloadWorkflow = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifactMain.id,
archive_format: "zip",
});
fs.writeFileSync(`${COMMIT_STRING_ARTIFACT}.zip`, Buffer.from(downloadWorkflow.data));
// Get output
const [matchArtifactMainOutput] = artifacts_main.data.artifacts.filter((artifact) =>
artifact.name === OUTPUT_ARTIFACT);
const downloadWorkflowTwo = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifactMainOutput.id,
archive_format: "zip",
});
fs.writeFileSync(`${OUTPUT_ARTIFACT}.zip`, Buffer.from(downloadWorkflowTwo.data));
return lastRunMain.head_sha;
- name: Copy and unzip the commit string
run: |
unzip primer_commitstring_${{ matrix.python-version }}.zip
cp commit_string_${{ matrix.python-version }}.txt tests/.pylint_primer_tests/commit_string_${{ matrix.python-version }}.txt
- name: Unzip the output of 'main'
run: |
unzip primer_output_main_${{ matrix.python-version }}_batch${{ matrix.batchIdx }}.zip
- name: Get commit string
id: commitstring
run: |
. venv/bin/activate
output=$(python tests/primer/__main__.py prepare --read-commit-string)
echo "commitstring=$output" >> $GITHUB_OUTPUT
- name: Restore projects cache
id: cache-projects
uses: actions/cache/restore@v4.3.0
with:
path: tests/.pylint_primer_tests/
key: >-
${{ runner.os }}-${{ matrix.python-version }}-${{
steps.commitstring.outputs.commitstring }}-primer
- name: Regenerate cache
if: steps.cache-projects.outputs.cache-hit != 'true'
run: |
. venv/bin/activate
python tests/primer/__main__.py prepare --clone
- name: Save projects cache
if: steps.cache-projects.outputs.cache-hit != 'true'
uses: actions/cache/save@v4.3.0
with:
path: tests/.pylint_primer_tests/
key: >-
${{ runner.os }}-${{ matrix.python-version }}-${{
steps.commitstring.outputs.commitstring }}-primer
- name: Check cache
run: |
. venv/bin/activate
python tests/primer/__main__.py prepare --check
# Merge the 'main' commit of last successful run
- name: Pull 'main'
shell: bash
run: |
git config --global user.email "primer@example.com"
git config --global user.name "Pylint Primer"
git pull origin ${{ steps.download-main-run.outputs.result }} --no-edit --no-commit --no-rebase
# Run primer
- name: Run pylint primer
run: |
. venv/bin/activate
pip install . --no-deps
python tests/primer/__main__.py run --type=pr --batches=${{ matrix.batches }} --batchIdx=${{ matrix.batchIdx }} 2>warnings.txt
- name: Echo warnings
if: success() || failure()
run: |
WARNINGS=$(head -c 65000 < warnings.txt)
if [[ $WARNINGS ]]
then echo "::warning ::$WARNINGS"
fi
- name: Upload output of PR
uses: actions/upload-artifact@v4.6.2
with:
name:
primer_output_pr_${{ matrix.python-version }}_batch${{ matrix.batchIdx }}
path:
tests/.pylint_primer_tests/output_${{ matrix.python-version }}_pr_batch${{
matrix.batchIdx }}.txt
- name: Upload output of 'main'
uses: actions/upload-artifact@v4.6.2
with:
name:
primer_output_main_${{ matrix.python-version }}_batch${{ matrix.batchIdx }}
path: output_${{ matrix.python-version }}_main_batch${{ matrix.batchIdx }}.txt
# Save PR number so we know which PR to comment on
- name: Save PR number
run: |
echo ${{ github.event.pull_request.number }} | tee pr_number.txt
- name: Upload PR number
if:
startsWith(steps.python.outputs.python-version, '3.10') && matrix.batchIdx ==
0
uses: actions/upload-artifact@v4.6.2
with:
name: pr_number
path: pr_number.txt

@ -1,80 +0,0 @@
name: Release
on:
release:
types:
- published
env:
DEFAULT_PYTHON: "3.13"
permissions:
contents: read
jobs:
build:
name: Build release assets
runs-on: ubuntu-latest
if: github.event_name == 'release'
steps:
- name: Check out code from Github
uses: actions/checkout@v5.0.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v6.0.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
- name: Install requirements
run: |
# Remove dist, build, and pylint.egg-info
# when building locally for testing!
python -m pip install build
- name: Build distributions
run: |
python -m build
- name: Upload release assets
uses: actions/upload-artifact@v4.6.2
with:
name: release-assets
path: dist/
release-pypi:
name: Upload release to PyPI
runs-on: ubuntu-latest
needs: ["build"]
environment:
name: PyPI
url: https://pypi.org/project/pylint/
permissions:
id-token: write
steps:
- name: Download release assets
uses: actions/download-artifact@v5.0.0
with:
name: release-assets
path: dist/
- name: Upload to PyPI
if: github.event_name == 'release'
uses: pypa/gh-action-pypi-publish@release/v1
release-github:
name: Upload assets to Github release
runs-on: ubuntu-latest
needs: ["build"]
permissions:
contents: write
id-token: write
steps:
- name: Download release assets
uses: actions/download-artifact@v5.0.0
with:
name: release-assets
path: dist/
- name: Sign the dists with Sigstore and upload assets to Github release
if: github.event_name == 'release'
uses: sigstore/gh-action-sigstore-python@v3.0.1
with:
inputs: |
./dist/*.tar.gz
./dist/*.whl

@ -1,44 +0,0 @@
name: close stale issues and pr
on:
schedule:
- cron: "30 1 * * *"
workflow_dispatch:
jobs:
close-issues:
if: github.repository_owner == 'pylint-dev'
runs-on: ubuntu-latest
permissions:
actions: write
issues: write
pull-requests: write
steps:
- uses: actions/stale@v10
with:
operations-per-run: 100
days-before-issue-stale: 28
days-before-issue-close: 7
any-of-issue-labels:
"Waiting on author,Cannot reproduce 🤷,python past end of life,Won't fix/not
planned"
exempt-issue-labels: "High priority,Blocked 🚧,Needs decision 🔒"
stale-issue-message:
"This issue is stale because it has been open 4 weeks with no activity.
Remove 'Stale' label or comment or this will be closed in a week."
close-issue-message:
"This issue was closed because it has been stalled for five weeks with no
activity."
any-of-pr-labels:
"Waiting on author,python past end of life,Won't fix/not planned"
exempt-pr-labels: "High priority,Blocked 🚧,Needs review 🔍"
days-before-pr-stale: 56
days-before-pr-close: -1
stale-pr-label: "Needs take over 🛎️"
close-pr-message:
"This PR was closed because it needed to be taken over for 16 weeks with no
one stepping up."
stale-pr-message:
"This PR needs take over because because it has been open 8 weeks with no
activity."

@ -1,208 +0,0 @@
name: Tests
on:
push:
branches:
- main
- "maintenance/**"
paths-ignore:
- doc/data/messages/**
pull_request:
branches:
- main
- "maintenance/**"
workflow_dispatch:
env:
CACHE_VERSION: 5
KEY_PREFIX: venv
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
tests:
name: run / ${{ matrix.python-version }} / ${{ matrix.os }}
timeout-minutes: 25
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
python-version: &matrix-python-version ["3.10", "3.11", "3.12", "3.13", "3.14"]
include:
- os: macos-latest
python-version: "3.10"
- os: ubuntu-latest
python-version: "pypy-3.10"
- os: ubuntu-latest
python-version: "pypy-3.11"
runs-on: ${{ matrix.os }}
outputs:
python-key: ${{ steps.generate-python-key.outputs.key }}
steps:
- &checkout
name: Check out code from GitHub
uses: actions/checkout@v5.0.0
- &setup-python
name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v6.0.0
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
check-latest: true
- name: Generate partial Python venv restore key
id: generate-python-key
run: >-
echo "key=${{ env.KEY_PREFIX }}-${{ env.CACHE_VERSION }}-${{
hashFiles('pyproject.toml', 'requirements_test.txt',
'requirements_test_min.txt', 'requirements_test_pre_commit.txt') }}" >>
$GITHUB_OUTPUT
- &cache-python
name: Restore Python virtual environment
id: cache-venv
uses: actions/cache@v4.3.0
with:
path: venv
key: >-
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
steps.generate-python-key.outputs.key }}
- name: Create Python virtual environment
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
python -m venv venv
. venv/bin/activate
python -m pip install --upgrade pip
pip install --upgrade --requirement requirements_test.txt
- name: Run pytest
run: |
. venv/bin/activate
pip install . --no-deps
pip list | grep 'astroid\|pylint'
python -m pytest --durations=10 --benchmark-disable --cov --cov-report= tests/
- name: Run functional tests with minimal messages config
run: |
. venv/bin/activate
pip list | grep 'astroid\|pylint'
python -m pytest -vv --minimal-messages-config tests/test_functional.py --benchmark-disable
- name: Upload coverage artifact
if: runner.os == 'Linux'
uses: actions/upload-artifact@v4.6.2
with:
name: coverage-${{ matrix.python-version }}
include-hidden-files: true
path: .coverage
coverage:
name: process / coverage
runs-on: ubuntu-latest
timeout-minutes: 5
needs: [tests]
steps:
- *checkout
- name: Set up Python 3.13
id: python
uses: actions/setup-python@v6.0.0
with:
python-version: "3.13"
check-latest: true
- &cache-restore-python
name: Restore Python virtual environment
id: cache-venv
uses: actions/cache/restore@v4.3.0
with:
path: venv
fail-on-cache-miss: true
key:
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
needs.tests.outputs.python-key }}
- name: Download all coverage artifacts
uses: actions/download-artifact@v5.0.0
- name: Combine coverage results
run: |
. venv/bin/activate
coverage combine coverage*/.coverage
coverage xml
- uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: true
verbose: true
benchmark-linux:
name: run benchmark / ${{ matrix.python-version }} / Linux
runs-on: ubuntu-latest
timeout-minutes: 10
needs: [tests]
strategy:
fail-fast: false
matrix:
python-version: ["3.13"]
steps:
- *checkout
- *setup-python
- *cache-restore-python
- name: Run pytest
run: |
. venv/bin/activate
pip install pygal
pip install . --no-deps
pip list | grep 'astroid\|pylint'
pytest --exitfirst \
--benchmark-only \
--benchmark-autosave \
--benchmark-save-data \
--benchmark-group-by="group"
- name: Create partial artifact name suffix
id: artifact-name-suffix
run: >-
echo "datetime="$(date "+%Y%m%d_%H%M") >> $GITHUB_OUTPUT
- name: Upload benchmark artifact
uses: actions/upload-artifact@v4.6.2
with:
name:
benchmark-${{ runner.os }}-${{ matrix.python-version }}_${{
steps.artifact-name-suffix.outputs.datetime }}
include-hidden-files: true
path: .benchmarks/
tests-windows:
name: run / ${{ matrix.python-version }} / Windows
runs-on: windows-latest
timeout-minutes: 25
needs: [tests]
strategy:
fail-fast: false
matrix:
python-version: *matrix-python-version
steps:
- name: Set temp directory
run: echo "TEMP=$env:USERPROFILE\AppData\Local\Temp" >> $env:GITHUB_ENV
# Workaround to set correct temp directory on Windows
# https://github.com/actions/virtual-environments/issues/712
- *checkout
- *setup-python
- name: Generate partial Python venv restore key
id: generate-python-key
run: >-
echo "key=venv-${{ env.CACHE_VERSION }}-${{
hashFiles('pyproject.toml', 'requirements_test_min.txt')
}}" >> $env:GITHUB_OUTPUT
- *cache-python
- name: Create Python virtual environment
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
python -m venv venv
. venv\\Scripts\\activate
python -m pip install --upgrade pip
pip install --upgrade --requirement requirements_test_min.txt
- name: Run pytest
run: |
. venv\\Scripts\\activate
pip install . --no-deps
pip list | grep 'astroid\|pylint'
python -m pytest --durations=10 --benchmark-disable tests/

@ -1,29 +0,0 @@
# Do not add entries specific to your dev environment or development
# preferences in this file. You can use the global .gitignore for that:
# git config --global core.excludesFile '~/.gitignore'
/log
*.py[cod]
/build
/doc/_build
/dist/
/pylint.egg-info/
.tox
*.sw[a-z]
# Can't use | operator in .gitignore, see
# https://unix.stackexchange.com/a/31806/189111
doc/user_guide/messages/convention/
doc/user_guide/messages/error/
doc/user_guide/messages/fatal/
doc/user_guide/messages/information/
doc/user_guide/messages/refactor/
doc/user_guide/messages/warning/
tests/.pylint_primer_tests/
pyve
build-stamp
.coverage
.coverage.*
.cache/
.eggs/
.pytest_cache/
.mypy_cache/
.benchmarks/

@ -1,174 +0,0 @@
ci:
skip: [pylint]
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: trailing-whitespace
exclude: tests(/\w*)*/functional/t/trailing_whitespaces.py|tests/pyreverse/data/.*.html|doc/data/messages/t/trailing-whitespace/bad.py
# - id: file-contents-sorter # commented out because it does not preserve comments order
# args: ["--ignore-case", "--unique"]
# files: "custom_dict.txt"
- id: end-of-file-fixer
exclude: |
(?x)^(
tests(/\w*)*/functional/m/missing/missing_final_newline.py|
tests/functional/t/trailing_newlines.py|
doc/data/messages/t/trailing-newlines/bad.py|
doc/data/messages/m/missing-final-newline/bad/lf.py|
doc/data/messages/m/missing-final-newline/bad/crlf.py
)$
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: "v0.14.0"
hooks:
- id: ruff-check
args: ["--fix"]
exclude: doc/data/messages
- id: ruff-check
name: ruff-doc
files: doc/data/messages
# Please exclude using doc/data/ruff.toml
# exclude: "" # Leave empty
- repo: https://github.com/Pierre-Sassoulas/copyright_notice_precommit
rev: 0.1.2
hooks:
- id: copyright-notice
args: ["--notice=script/copyright.txt", "--enforce-all"]
exclude: tests(/\w*)*/functional/|tests/input|doc/data/messages|examples/|setup.py|tests(/\w*)*data/
types: [python]
- repo: https://github.com/PyCQA/isort
rev: 7.0.0
hooks:
- id: isort
exclude: doc/data/messages/
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 25.9.0
hooks:
- id: black
args: [--safe, --quiet]
exclude: &fixtures tests(/\w*)*/functional/|tests/input|doc/data/messages|tests(/\w*)*data/
- id: black
name: black-doc
args: [--safe, --quiet]
files: doc/data/messages/
exclude: |
(?x)^(
doc/data/messages/b/bad-indentation/bad.py|
doc/data/messages/i/inconsistent-quotes/bad.py|
doc/data/messages/i/invalid-format-index/bad.py|
doc/data/messages/l/line-too-long/bad.py|
doc/data/messages/m/missing-final-newline/bad/crlf.py|
doc/data/messages/m/missing-final-newline/bad/lf.py|
doc/data/messages/m/multiple-statements/bad.py|
doc/data/messages/r/redundant-u-string-prefix/bad.py|
doc/data/messages/s/superfluous-parens/bad/example_1.py|
doc/data/messages/s/syntax-error/bad.py|
doc/data/messages/t/too-many-ancestors/bad.py|
doc/data/messages/t/trailing-comma-tuple/bad.py|
doc/data/messages/t/trailing-newlines/bad.py|
doc/data/messages/t/trailing-whitespace/bad.py|
doc/data/messages/u/unnecessary-semicolon/bad.py
)$
- repo: https://github.com/Pierre-Sassoulas/black-disable-checker
rev: v1.1.3
hooks:
- id: black-disable-checker
- repo: local
hooks:
- id: pylint
name: pylint
entry: pylint
language: system
types: [python]
# Not that problematic to run in parallel see Pre-commit
# integration in the doc for details
# require_serial: true
args: ["-rn", "-sn", "--rcfile=pylintrc", "--fail-on=I"]
exclude: tests(/\w*)*/functional/|tests/input|tests(/\w*)*data/|doc/
- id: pyright
name: pyright
description: "Python command line wrapper for pyright, a static type checker"
entry: pyright
language: python
"types_or": [python, pyi]
require_serial: true
minimum_pre_commit_version: "2.9.2"
exclude: tests(/\w*)*/functional/|tests/input|tests(/.*)+/conftest.py|doc/data/messages|tests(/\w*)*data/
stages: [manual]
# We define an additional manual step to allow running pylint with a spelling
# checker in CI.
- id: pylint
alias: pylint-with-spelling
name: pylint
entry: pylint
language: system
types: [python]
args:
[
"-rn",
"-sn",
"--rcfile=pylintrc",
"--fail-on=I",
"--spelling-dict=en",
"--output-format=github",
]
exclude: tests(/\w*)*/functional/|tests/input|tests(/\w*)*data/|doc/
stages: [manual]
- id: check-newsfragments
name: Check newsfragments
entry: python3 -m script.check_newsfragments
language: system
types: [text]
files: ^(doc/whatsnew/fragments)
exclude: doc/whatsnew/fragments/_.*.rst
- repo: https://github.com/rstcheck/rstcheck
rev: "v6.2.5"
hooks:
- id: rstcheck
args: ["--report-level=warning"]
files: ^(doc/(.*/)*.*\.rst)
additional_dependencies: ["Sphinx==7.4.3"]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.18.2
hooks:
- id: mypy
name: mypy
args: []
additional_dependencies:
["isort>=5", "platformdirs==2.2.0", "py==1.11", "tomlkit>=0.10.1"]
exclude: tests(/\w*)*/functional/|tests/input|tests(/.*)+/conftest.py|doc/data/messages|tests(/\w*)*data/
- repo: https://github.com/rbubley/mirrors-prettier
rev: v3.6.2
hooks:
- id: prettier
args: [--prose-wrap=always, --print-width=88]
exclude: (tests(/\w*)*data/|.github/FUNDING.yml)
- repo: https://github.com/DanielNoord/pydocstringformatter
rev: v0.7.5
hooks:
- id: pydocstringformatter
exclude: *fixtures
args: ["--max-summary-lines=2", "--linewrap-full-docstring"]
files: "pylint"
- repo: https://github.com/PyCQA/bandit
rev: 1.8.6
hooks:
- id: bandit
args: ["-r", "-lll"]
exclude: *fixtures
- repo: https://github.com/codespell-project/codespell
rev: v2.4.1
hooks:
- id: codespell
args: ["--toml=pyproject.toml"]
additional_dependencies:
- tomli
- repo: https://github.com/tox-dev/pyproject-fmt
rev: "v2.10.0"
hooks:
- id: pyproject-fmt
- repo: https://github.com/abravalheri/validate-pyproject
rev: v0.24.1
hooks:
- id: validate-pyproject

@ -1,6 +0,0 @@
- id: pylint
name: pylint
entry: pylint
language: python
types: [python]
require_serial: true

@ -1,19 +0,0 @@
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
version: 2
sphinx:
fail_on_warning: true
configuration: doc/conf.py
python:
install:
- requirements: doc/readthedoc_requirements.txt
build:
os: ubuntu-22.04
tools:
python: "3.11"
jobs:
pre_build:
- towncrier build --yes --date TBA

@ -1,14 +0,0 @@
cff-version: 1.2.0
title: "Pylint"
message: >-
If you use this software, please cite it using the metadata from this file.
type: software
authors:
- name: "Pylint contributors"
repository-code: "https://github.com/pylint-dev/pylint"
url: "https://pylint.readthedocs.io/en/latest/"
abstract: >-
Pylint is a static code analyser for Python 2 or 3. Pylint analyses your code without
actually running it. It checks for errors, enforces a coding standard, looks for code
smells, and can make suggestions about how the code could be refactored.
license: GPL-2.0

@ -1,120 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our community a
harassment-free experience for everyone, regardless of age, body size, visible or
invisible disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal appearance,
race, religion, or sexual identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming, diverse,
inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our community
include:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes, and
learning from the experience
- Focusing on what is best not just for us as individuals, but for the overall community
Examples of unacceptable behavior include:
- The use of sexualized language or imagery, and sexual attention or advances of any
kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email address, without
their explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional
setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in response to
any behavior that they deem inappropriate, threatening, offensive, or harmful.
Community leaders have the right and responsibility to remove, edit, or reject comments,
commits, code, wiki edits, issues, and other contributions that are not aligned to this
Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when an
individual is officially representing the community in public spaces. Examples of
representing our community include using an official e-mail address, posting via an
official social media account, or acting as an appointed representative at an online or
offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to
the community leaders responsible for enforcement at pierre.sassoulas at gmail.com. All
complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the reporter
of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining the
consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing clarity
around the nature of the violation and an explanation of why the behavior was
inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of actions.
**Consequence**: A warning with consequences for continued behavior. No interaction with
the people involved, including unsolicited interaction with those enforcing the Code of
Conduct, for a specified period of time. This includes avoiding interactions in
community spaces as well as external channels like social media. Violating these terms
may lead to a temporary or permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including sustained
inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public communication
with the community for a specified period of time. No public or private interaction with
the people involved, including unsolicited interaction with those enforcing the Code of
Conduct, is allowed during this period. Violating these terms may lead to a permanent
ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community standards,
including sustained inappropriate behavior, harassment of an individual, or aggression
toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0,
available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

@ -1,699 +0,0 @@
# This file is autocompleted by 'contributors-txt',
# using the configuration in 'script/.contributors_aliases.json'.
# Do not add new persons manually and only add information without
# using '-' as the line first character.
# Please verify that your change are stable if you modify manually.
Ex-maintainers
--------------
- Claudiu Popa <pcmanticore@gmail.com>
- Sylvain Thénault <thenault@gmail.com> : main author / maintainer
- Torsten Marek <shlomme@gmail.com>
Maintainers
-----------
- Pierre Sassoulas <pierre.sassoulas@gmail.com>
- Daniël van Noord <13665637+DanielNoord@users.noreply.github.com>
- Jacob Walls <jacobtylerwalls@gmail.com>
- Marc Mueller <30130371+cdce8p@users.noreply.github.com>
- Hippo91 <guillaume.peillex@gmail.com>
- Mark Byrne <31762852+mbyrnepr2@users.noreply.github.com>
- Andreas Finkler <3929834+DudeNr33@users.noreply.github.com>
- Matus Valo <matusvalo@users.noreply.github.com>
- Dani Alcala <112832187+clavedeluna@users.noreply.github.com>
- Łukasz Rogalski <rogalski.91@gmail.com>
- Nick Drozd <nicholasdrozd@gmail.com>: performance improvements to astroid
- Ashley Whetter <ashley@awhetter.co.uk>
- Bryce Guinta <bryce.paul.guinta@gmail.com>
- Yu Shao, Pang <36848472+yushao2@users.noreply.github.com>
- Dimitri Prybysh <dmand@yandex.ru>
* multiple-imports, not-iterable, not-a-mapping, various patches.
- Roy Williams <roy.williams.iii@gmail.com> (Lyft)
* added check for implementing __eq__ without implementing __hash__,
* Added Python 3 check for accessing Exception.message.
* Added Python 3 check for calling encode/decode with invalid codecs.
* Added Python 3 check for accessing sys.maxint.
* Added Python 3 check for bad import statements.
* Added Python 3 check for accessing deprecated methods on the 'string' module,
various patches.
- Florian Bruhin <me@the-compiler.org>
- Arianna Yang <areveny@protonmail.com>
Contributors
------------
We would not be here without folks that contributed patches, pull requests,
issues and their time to pylint. We're incredibly grateful to all of these
contributors:
- Emile Anclin <emile.anclin@logilab.fr> (Logilab): python 3 support
- Michal Nowikowski <godfryd@gmail.com>:
* wrong-spelling-in-comment
* wrong-spelling-in-docstring
* parallel execution on multiple CPUs
- Julthep Nandakwang <julthep@nandakwang.com>
- Bruno Daniel <bruno.daniel@blue-yonder.com>: check_docs extension.
- Sushobhit <31987769+sushobhit27@users.noreply.github.com> (sushobhit27)
* Added new check 'comparison-with-itself'.
* Added new check 'useless-import-alias'.
* Added support of annotations in missing-type-doc and missing-return-type-doc.
* Added new check 'comparison-with-callable'.
* Removed six package dependency.
* Added new check 'chained-comparison'.
* Added new check 'useless-object-inheritance'.
- Brett Cannon <brett@python.org>:
* Port source code to be Python 2/3 compatible
* Python 3 checker
- Laura Médioni <laura.medioni@logilab.fr> (Logilab, on behalf of the CNES):
* misplaced-comparison-constant
* no-classmethod-decorator
* no-staticmethod-decorator
* too-many-nested-blocks,
* too-many-boolean-expressions
* unneeded-not
* wrong-import-order
* ungrouped-imports,
* wrong-import-position
* redefined-variable-type
- Harutaka Kawamura <hkawamura0130@gmail.com>
- Alexandre Fayolle <alexandre.fayolle@logilab.fr> (Logilab): TkInter gui, documentation, debian support
- Ville Skyttä <ville.skytta@iki.fi>
- Zen Lee <53538590+zenlyj@users.noreply.github.com>
- Julien Cristau <julien.cristau@logilab.fr> (Logilab): python 3 support
- Moisés López <6644187+moylop260@users.noreply.github.com>:
* Support for deprecated-modules in modules not installed,
* Refactor wrong-import-order to integrate it with `isort` library
* Add check too-complex with mccabe for cyclomatic complexity
* Refactor wrong-import-position to skip try-import and nested cases
* Add consider-merging-isinstance, superfluous-else-return
* Fix consider-using-ternary for 'True and True and True or True' case
* Add bad-docstring-quotes and docstring-first-line-empty
* Add missing-timeout
* Fix false negative for `deprecated-module` when a `__import__` method is used instead of `import` sentence
- Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
- Frank Harrison <frank@doublethefish.com> (doublethefish)
- Pierre-Yves David <pierre-yves.david@logilab.fr>
- David Shea <dshea@redhat.com>: invalid sequence and slice index
- Gunung P. Wibisono <55311527+gunungpw@users.noreply.github.com>
- Derek Gustafson <degustaf@gmail.com>
- Cezar Elnazli <cezar.elnazli2@gmail.com>: deprecated-method
- Joseph Young <80432516+jpy-git@users.noreply.github.com> (jpy-git)
- Tim Martin <tim@asymptotic.co.uk>
- Ollie <46904826+ollie-iterators@users.noreply.github.com>
- Julian Grimm <51880314+Julfried@users.noreply.github.com>
- Tushar Sadhwani <tushar.sadhwani000@gmail.com> (tusharsadhwani)
- Nicolas Chauvat <nicolas.chauvat@logilab.fr>
- orSolocate <38433858+orSolocate@users.noreply.github.com>
- Radu Ciorba <radu@devrandom.ro>: not-context-manager and confusing-with-statement warnings.
- Holger Peters <email@holger-peters.de>
- Cosmin Poieană <cmin@ropython.org>: unichr-builtin and improvements to bad-open-mode.
- Yilei "Dolee" Yang <yileiyang@google.com>
- Steven Myint <hg@stevenmyint.com>: duplicate-except.
- Peter Kolbus <peter.kolbus@gmail.com> (Garmin)
- Luigi Bertaco Cristofolini <lucristofolini@gmail.com> (luigibertaco)
- Glenn Matthews <glenn@e-dad.net>:
* autogenerated documentation for optional extensions,
* bug fixes and enhancements for docparams (née check_docs) extension
- crazybolillo <antonio@zoftko.com>
- correctmost <134317971+correctmost@users.noreply.github.com>
- Vlad Temian <vladtemian@gmail.com>: redundant-unittest-assert and the JSON reporter.
- Julien Jehannet <julien.jehannet@logilab.fr>
- Boris Feld <lothiraldan@gmail.com>
- Anthony Sottile <asottile@umich.edu>
- Andrew Haigh <nelfin@gmail.com> (nelfin)
- Robert Hofer <hofrob@protonmail.com>
- Pedro Algarvio <pedro@algarvio.me> (s0undt3ch)
- Julien Palard <julien@palard.fr>
- Hugo van Kemenade <hugovk@users.noreply.github.com>
- David Liu <david@cs.toronto.edu> (david-yz-liu)
- Dan Goldsmith <djgoldsmith@googlemail.com>: support for msg-template in HTML reporter.
- Buck Evan <buck.2019@gmail.com>
- Mariatta Wijaya <Mariatta@users.noreply.github.com>
* Added new check `logging-fstring-interpolation`
* Documentation typo fixes
- Jakub Wilk <jwilk@jwilk.net>
- Eli Fine <ejfine@gmail.com> (eli88fine): Fixed false positive duplicate code warning for lines with symbols only
- Émile Crater <emile@crater.logilab.fr>
- Pavel Roskin <proski@gnu.org>
- David Gilman <davidgilman1@gmail.com>
- へーさん <hira9603859504@gmail.com>
- Thomas Hisch <t.hisch@gmail.com>
- Marianna Polatoglou <mpolatoglou@bloomberg.net>: minor contribution for wildcard import check
- Manuel Vázquez Acosta <mva.led@gmail.com>
- Luis Escobar <lescobar@vauxoo.com> (Vauxoo): Add bad-docstring-quotes and docstring-first-line-empty
- Lucas Cimon <lucas.cimon@gmail.com>
- Konstantina Saketou <56515303+ksaketou@users.noreply.github.com>
- Konstantin <Github@pheanex.de>
- Jim Robertson <jrobertson98atx@gmail.com>
- Ethan Leba <ethanleba5@gmail.com>
- Enji Cooper <yaneurabeya@gmail.com>
- Drum Ogilvie <me@daogilvie.com>
- David Lindquist <dlindquist@google.com>: logging-format-interpolation warning.
- Daniel Harding <dharding@gmail.com>
- Anthony Truchet <anthony.truchet@logilab.fr>
- Alexander Todorov <atodorov@otb.bg>:
* added new error conditions to 'bad-super-call',
* Added new check for incorrect len(SEQUENCE) usage,
* Added new extension for comparison against empty string constants,
* Added new extension which detects comparing integers to zero,
* Added new useless-return checker,
* Added new try-except-raise checker
- theirix <theirix@gmail.com>
- Téo Bouvard <teobouvard@gmail.com>
- Sviatoslav Sydorenko <sviat@redhat.com>
- Stavros Ntentos <133706+stdedos@users.noreply.github.com>
- Nicolas Boulenguez <nicolas@debian.org>
- Mihai Balint <balint.mihai@gmail.com>
- Mark Bell <mark00bell@googlemail.com>
- Levi Gruspe <mail.levig@gmail.com>
- Jakub Kuczys <me@jacken.men>
- Hornwitser <github@hornwitser.no>: fix import graph
- Fureigh <rhys.fureigh@gsa.gov>
- David Douard <david.douard@sdfa3.org>
- Daniel Balparda <balparda@google.com> (Google): GPyLint maintainer (Google's pylint variant)
- Christian Clauss <cclauss@me.com>
- Bastien Vallet <bastien.vallet@gmail.com> (Djailla)
- Aru Sahni <arusahni@gmail.com>: Git ignoring, regex-based ignores
- Andreas Freimuth <andreas.freimuth@united-bits.de>: fix indentation checking with tabs
- Alexandru Coman <fcoman@bitdefender.com>
- jpkotta <jpkotta@gmail.com>
- Thomas Grainger <tagrain@gmail.com>
- Takahide Nojima <nozzy123nozzy@gmail.com>
- Taewon D. Kim <kimt33@mcmaster.ca>
- Sneaky Pete <sneakypete81@gmail.com>
- Sergey B Kirpichev <skirpichev@gmail.com>
- Sandro Tosi <sandro.tosi@gmail.com>: Debian packaging
- Rogdham <contact@rogdham.net>
- Rene Zhang <rz99@cornell.edu>
- Paul Lichtenberger <paul.lichtenberger.rgbg@gmail.com>
- Or Bahari <or.ba402@gmail.com>
- Mr. Senko <atodorov@mrsenko.com>
- Mike Frysinger <vapier@gmail.com>
- Martin von Gagern <gagern@google.com> (Google): Added 'raising-format-tuple' warning.
- Martin Vielsmaier <martin@vielsmaier.net>
- Martin Pool <mbp@google.com> (Google):
* warnings for anomalous backslashes
* symbolic names for messages (like 'unused')
* etc.
- Martin Bašti <MartinBasti@users.noreply.github.com>
* Added new check for shallow copy of os.environ
* Added new check for useless `with threading.Lock():` statement
- Marcus Näslund <naslundx@gmail.com> (naslundx)
- Marco Pernigotti <7657251+mpernigo@users.noreply.github.com>
- Marco Forte <fortemarco.irl@gmail.com>
- James Addison <55152140+jayaddison@users.noreply.github.com>
- Ionel Maries Cristian <contact@ionelmc.ro>
- Gergely Kalmár <gergely.kalmar@logikal.jp>
- Damien Baty <damien.baty@polyconseil.fr>
- Benjamin Drung <benjamin.drung@profitbricks.com>: contributing Debian Developer
- Anubhav <35621759+anubh-v@users.noreply.github.com>
- Antonio Quarta <sgheppy88@gmail.com>
- Andrew J. Simmons <anjsimmo@gmail.com>
- Alvaro Frias <alvarofriasgaray@gmail.com>
- Alexey Pelykh <alexey.pelykh@gmail.com>
- Alex Prabhat Bara <alexpbara@gmail.com>
- wtracy <afishionado@gmail.com>
- jessebrennan <jesse@jesse.computer>
- chohner <mail@chohner.com>
- aatle <168398276+aatle@users.noreply.github.com>
- Tiago Honorato <61059243+tiagohonorato@users.noreply.github.com>
- Steven M. Vascellaro <svascellaro@gmail.com>
- Robin Tweedie <70587124+robin-wayve@users.noreply.github.com>
- Roberto Leinardi <leinardi@gmail.com>: PyCharm plugin maintainer
- Ricardo Gemignani <ricardo.gemignani@gmail.com>
- Piotr Idzik <65706193+vil02@users.noreply.github.com>
- Pieter Engelbrecht <pengelbrecht@rems2.com>
- Philipp Albrecht <flying-sheep@web.de> (pylbrecht)
- Nicolas Dickreuter <dickreuter@gmail.com>
- Nick Bastin <nick.bastin@gmail.com>
- Nathaniel Manista <nathaniel@google.com>: suspicious lambda checking
- Maksym Humetskyi <Humetsky@gmail.com> (mhumetskyi)
* Fixed ignored empty functions by similarities checker with "ignore-signatures" option enabled
* Ignore function decorators signatures as well by similarities checker with "ignore-signatures" option enabled
* Ignore class methods and nested functions signatures as well by similarities checker with "ignore-signatures" option enabled
- Kylian <development@goudcode.nl>
- Konstantin Manna <Konstantin@Manna.uno>
- Kai Mueller <15907922+kasium@users.noreply.github.com>
- Joshua Cannon <joshdcannon@gmail.com>
- John Leach <jfleach@jfleach.com>
- James Morgensen <james.morgensen@gmail.com>: ignored-modules option applies to import errors.
- Jaehoon Hwang <jaehoonhwang@users.noreply.github.com> (jaehoonhwang)
- Huw Jones <huw@huwcbjones.co.uk>
- Gideon <87426140+GideonBear@users.noreply.github.com>
- Ganden Schaffner <gschaffner@pm.me>
- Frost Ming <frostming@tencent.com>
- Federico Bond <federicobond@gmail.com>
- Erik Wright <erik.wright@shopify.com>
- Erik Eriksson <molobrakos@users.noreply.github.com>: Added overlapping-except error check.
- Emmanuel Ferdman <emmanuelferdman@gmail.com>
- Dave Bunten <dave.bunten@cuanschutz.edu>
- Daniel Wang <danielwang405@gmail.com>
- Daniel Mouritzen <dmrtzn@gmail.com>
- Dan Hemberger <846186+hemberger@users.noreply.github.com>
- Chris Rebert <code@rebertia.com>: unidiomatic-typecheck.
- Aurelien Campeas <aurelien.campeas@logilab.fr>
- Alexander Pervakov <frost.nzcr4@jagmort.com>
- Alain Leufroy <alain.leufroy@logilab.fr>
- Akhil Kamat <akhil.kamat@gmail.com>
- Adam Williamson <awilliam@redhat.com>
- Aaron Liu <aaronliu0130@gmail.com>
- xmo-odoo <xmo-odoo@users.noreply.github.com>
- tbennett0 <tbennett0@users.noreply.github.com>
- purajit <7026198+purajit@users.noreply.github.com>
- omarandlorraine <64254276+omarandlorraine@users.noreply.github.com>
- craig-sh <craig-sh@users.noreply.github.com>
- bernie gray <bfgray3@users.noreply.github.com>
- azinneck0485 <123660683+azinneck0485@users.noreply.github.com>
- Wing Lian <wing.lian@gmail.com>
- Wes Turner <westurner@google.com> (Google): added new check 'inconsistent-quotes'
- Tyler Thieding <tyler@thieding.com>
- Tobias Hernstig <30827238+thernstig@users.noreply.github.com>
- Smixi <sismixx@hotmail.fr>
- Simu Toni <simutoni@gmail.com>
- Sergei Lebedev <185856+superbobry@users.noreply.github.com>
- Scott Worley <scottworley@scottworley.com>
- Saugat Pachhai <suagatchhetri@outlook.com>
- Samuel FORESTIER <HorlogeSkynet@users.noreply.github.com>
- Rémi Cardona <remi.cardona@polyconseil.fr>
- Ryan Ozawa <ryan.ozawa21@gmail.com>
- Roger Sheu <78449574+rogersheu@users.noreply.github.com>
- Raphael Gaschignard <raphael@makeleaps.com>
- Ram Rachum <ram@rachum.com> (cool-RR)
- Radostin Stoyanov <rst0git@users.noreply.github.com>
- Peter Bittner <django@bittner.it>
- Paul Renvoisé <PaulRenvoise@users.noreply.github.com>
- PHeanEX <github@pheanex.de>
- Omega Weapon <OmegaPhil+hg@gmail.com>
- Nikolai Kristiansen <nikolaik@gmail.com>
- Nick Pesce <nickpesce22@gmail.com>
- Nedelcu Ioan-Andrei <138256980+nedelcu-ioan@users.noreply.github.com>
- Nathan Marrow <nmarrow@google.com>
- Mikhail Fesenko <m.fesenko@corp.vk.com>
- Matthew Suozzo <msuozzo@google.com>
- Matthew Beckers <17108752+mattlbeck@users.noreply.github.com> (mattlbeck)
- Mark Roman Miller <mtmiller@users.noreply.github.com>: fix inline defs in too-many-statements
- MalanB <malan.kmu@gmail.com>
- Mads Kiilerich <mads@kiilerich.com>
- Maarten ter Huurne <maarten@treewalker.org>
- Lefteris Karapetsas <lefteris@refu.co>
- LCD 47 <lcd047@gmail.com>
- Jérome Perrin <perrinjerome@gmail.com>
- Justin Li <justinnhli@gmail.com>
- John Kirkham <jakirkham@gmail.com>
- Jens H. Nielsen <Jens.Nielsen@microsoft.com>
- Jake Lishman <jake.lishman@ibm.com>
- Ioana Tagirta <ioana.tagirta@gmail.com>: fix bad thread instantiation check
- Ikraduya Edian <ikraduya@gmail.com>: Added new checks 'consider-using-generator' and 'use-a-generator'.
- Hugues Bruant <hugues.bruant@affirm.com>
- Hashem Nasarat <Hnasar@users.noreply.github.com>
- Harut <yes@harutune.name>
- Grygorii Iermolenko <gyermolenko@gmail.com>
- Grizzly Nyo <grizzly.nyo@gmail.com>
- Gabriel R. Sezefredo <g@briel.dev>: Fixed "exception-escape" false positive with generators
- Filipe Brandenburger <filbranden@google.com>
- Fantix King <fantix@uchicago.edu> (UChicago)
- Eric McDonald <221418+emcd@users.noreply.github.com>
- Elias Dorneles <eliasdorneles@gmail.com>: minor adjust to config defaults and docs
- Elazrod56 <thomas.lf5629@gmail.com>
- Edward K. Ream <edreamleo@gmail.com>
- Derek Harland <derek.harland@finq.co.nz>
- David Pursehouse <david.pursehouse@gmail.com>
- Daniel Miller <millerdev@gmail.com>
- Christoph Blessing <33834216+cblessing24@users.noreply.github.com>
- Chris Murray <chris@chrismurray.scot>
- Chris Lamb <chris@chris-lamb.co.uk>
- Charles Hebert <charles.hebert@logilab.fr>
- Carli Freudenberg <carli.freudenberg@energymeteo.de> (CarliJoy)
* Fixed issue 5281, added Unicode checker
* Improve non-ascii-name checker
- Bruce Dawson <randomascii@users.noreply.github.com>
- Brian Shaginaw <brian.shaginaw@warbyparker.com>: prevent error on exception check for functions
- Benny Mueller <benny.mueller91@gmail.com>
- Ben James <benjames1999@hotmail.co.uk>
- Ben Green <benhgreen@icloud.com>
- Batuhan Taskaya <batuhanosmantaskaya@gmail.com>
- Artem Yurchenko <artemyurchenko@zoho.com>
- Alexander Kapshuna <kapsh@kap.sh>
- Akshay Choudhary <153769403+Akshay9715@users.noreply.github.com>
- Adam Parkin <pzelnip@users.noreply.github.com>
- 谭九鼎 <109224573@qq.com>
- Łukasz Sznuk <ls@rdprojekt.pl>
- zasca <gorstav@gmail.com>
- y2kbugger <y2kbugger@users.noreply.github.com>
- vinnyrose <vinnyrose@users.noreply.github.com>
- ttenhoeve-aa <ttenhoeve@appannie.com>
- thinwybk <florian.k@mailbox.org>
- temyurchenko <44875844+temyurchenko@users.noreply.github.com>
- syutbai <syutbai@gmail.com>
- sur.la.route <17788706+christopherpickering@users.noreply.github.com>
- sdet_liang <liangway@users.noreply.github.com>
- pavan-msys <149513767+pavan-msys@users.noreply.github.com>
- paschich <millen@gridium.com>
- oittaa <8972248+oittaa@users.noreply.github.com>
- nyabkun <75878387+nyabkun@users.noreply.github.com>
- nhdsd <wyx070906@outlook.com>
- moxian <aleftmail@inbox.ru>
- mar-chi-pan <mar.polatoglou@gmail.com>
- lrjball <50599110+lrjball@users.noreply.github.com>
- levon-d <mycroft2003@gmail.com>
- laike9m <laike9m@users.noreply.github.com>
- kyoto7250 <50972773+kyoto7250@users.noreply.github.com>
- kriek <sylvain.ackermann@gmail.com>
- kdestin <101366538+kdestin@users.noreply.github.com>
- jaydesl <35102795+jaydesl@users.noreply.github.com>
- jab <jab@users.noreply.github.com>
- gracejiang16 <70730457+gracejiang16@users.noreply.github.com>
- glmdgrielson <32415403+glmdgrielson@users.noreply.github.com>
- glegoux <gilles.legoux@gmail.com>
- gaurikholkar <f2013002@goa.bits-pilani.ac.in>
- flyingbot91 <flyingbot91@gmx.com>
- fly <fly@users.noreply.github.com>
- fahhem <fahhem>
- fadedDexofan <fadedDexofan@gmail.com>
- epenet <6771947+epenet@users.noreply.github.com>
- danields <danields761@gmail.com>
- cosven <cosven@users.noreply.github.com>
- cordis-dev <darius@adroiti.com>
- cherryblossom <31467609+cherryblossom000@users.noreply.github.com>
- bluesheeptoken <louis.fruleux1@gmail.com>
- anatoly techtonik <techtonik@gmail.com>
- amelenty <ada.melentyeva@gmail.com>
- akirchhoff-modular <github-work@kirchhoff.digital>
- agutole <toldo_carp@hotmail.com>
- Zeckie <49095968+Zeckie@users.noreply.github.com>
- Zeb Nicholls <zebedee.nicholls@climate-energy-college.org>
* Made W9011 compatible with 'of' syntax in return types
- Yuval Langer <yuvallanger@mail.tau.ac.il>
- Yury Gribov <tetra2005@gmail.com>
- Yuri Bochkarev <baltazar.bz@gmail.com>: Added epytext support to docparams extension.
- Youngsoo Sung <ysung@bepro11.com>
- Yory <39745367+yory8@users.noreply.github.com>
- Yoichi Nakayama <yoichi.nakayama@gmail.com>
- Yeting Li <liyt@ios.ac.cn> (yetingli)
- Yannack <yannack@users.noreply.github.com>
- Yann Dirson <ydirson@free.fr>
- Yang Yang <y4n9squared@gmail.com>
- Xi Shen <davidshen84@gmail.com>
- Winston H <56998716+winstxnhdw@users.noreply.github.com>
- Will Shanks <wsha@posteo.net>
- Viorel Știrbu <viorels@gmail.com>: intern-builtin warning.
- VictorT <victor.taix@gmail.com>
- Victor Jiajunsu <16359131+jiajunsu@users.noreply.github.com>
- ViRuSTriNiTy <cradle-of-mail@gmx.de>
- Val Lorentz <progval+github@progval.net>
- Ulrich Eckhardt <UlrichEckhardt@users.noreply.github.com>
- Udi Fuchs <udifuchs@gmail.com>
- Trevor Bekolay <tbekolay@gmail.com>
* Added --list-msgs-enabled command
- Tomer Chachamu <tomer.chachamu@gmail.com>: simplifiable-if-expression
- Tomasz Michalski <tomasz.michalski@rtbhouse.com>
- Tomasz Magulski <tomasz@magullab.io>
- Tom <tsarantis@proton.me>
- Tim Hatch <tim@timhatch.com>
- Tim Gates <tim.gates@iress.com>
- Tianyu Chen <124018391+UTsweetyfish@users.noreply.github.com>
- Théo Battrel <theo.util@protonmail.ch>
- Thomas Benhamou <thomas@lightricks.com>
- Theodore Ni <3806110+tjni@users.noreply.github.com>
- Tanvi Moharir <74228962+tanvimoharir@users.noreply.github.com>: Fix for invalid toml config
- T.Rzepka <Tobias.Rzepka@gmail.com>
- Svetoslav Neykov <svet@hyperscience.com>
- SubaruArai <78188579+SubaruArai@users.noreply.github.com>
- Stéphane Wirtel <stephane@wirtel.be>: nonlocal-without-binding
- Stephen Longofono <8992396+SLongofono@users.noreply.github.com>
- Stephane Odul <1504511+sodul@users.noreply.github.com>
- Stanislav Levin <slev@altlinux.org>
- Sorin Sbarnea <ssbarnea@redhat.com>
- Slavfox <slavfoxman@gmail.com>
- Skip Montanaro <skip@pobox.com>
- Sigurd Spieckermann <2206639+sisp@users.noreply.github.com>
- Shiv Venkatasubrahmanyam <shvenkat@users.noreply.github.com>
- Sebastian Müller <mueller.seb@posteo.de>
- Sayyed Faisal Ali <80758388+C0DE-SLAYER@users.noreply.github.com>
- Sasha Bagan <pnlbagan@gmail.com>
- Sardorbek Imomaliev <sardorbek.imomaliev@gmail.com>
- Santiago Castro <bryant@montevideo.com.uy>
- Samuel Freilich <sfreilich@google.com> (sfreilich)
- Sam Vermeiren <88253337+PaaEl@users.noreply.github.com>
- Ryan McGuire <ryan@enigmacurry.com>
- Ry4an Brase <ry4an-hg@ry4an.org>
- Ruro <ruro.ruro@ya.ru>
- Roshan Shetty <roshan.shetty2816@gmail.com>
- Roman Ivanov <me@roivanov.com>
- Robert Schweizer <robert_schweizer@gmx.de>
- Reverb Chu <reverbc@users.noreply.github.com>
- Renat Galimov <renat2017@gmail.com>
- Rebecca Turner <rbt@sent.as> (9999years)
- Randall Leeds <randall@bleeds.info>
- Ranadheer Gorrepati <35244169+ranadheerg@users.noreply.github.com>
- Ramon Saraiva <ramonsaraiva@gmail.com>
- Ramiro Leal-Cavazos <ramiroleal050@gmail.com> (ramiro050): Fixed bug preventing pylint from working with Emacs tramp
- RSTdefg <34202999+RSTdefg@users.noreply.github.com>
- R. N. West <98110034+rnwst@users.noreply.github.com>
- Qwiddle13 <32040075+Qwiddle13@users.noreply.github.com>
- Quentin Young <qlyoung@users.noreply.github.com>
- Prajwal Borkar <sunnyborkar7777@gmail.com>
- Petr Pulc <petrpulc@gmail.com>: require whitespace around annotations
- Peter Dawyndt <Peter.Dawyndt@UGent.be>
- Peter Dave Hello <hsu@peterdavehello.org>
- Peter Aronoff <peter@aronoff.org>
- Paul Cochrane <paul@liekut.de>
- Patrik <patrik.mrx@gmail.com>
- Pascal Corpet <pcorpet@users.noreply.github.com>
- Pablo Galindo Salgado <Pablogsal@gmail.com>
* Fix false positive 'Non-iterable value' with async comprehensions.
- Osher De Paz <odepaz@redhat.com>
- Oisín Moran <OisinMoran@users.noreply.github.com>
- Obscuron <Abscuron@gmail.com>
- Noam Yorav-Raphael <noamraph@gmail.com>
- Noah-Agnel <138210920+Noah-Agnel@users.noreply.github.com>
- Nir Soffer <nirsof@gmail.com>
- Niko Wenselowski <niko@nerdno.de>
- Nikita Sobolev <mail@sobolevn.me>
- Nick Smith <clickthisnick@users.noreply.github.com>
- Neowizard <Neowizard@users.noreply.github.com>
- Ned Batchelder <ned@nedbatchelder.com>
- Natalie Serebryakova <natalie.serebryakova@Natalies-MacBook-Pro.local>
- Naglis Jonaitis <827324+naglis@users.noreply.github.com>
- Moody <mooodyhunter@outlook.com>
- Mitchell Young <mitchelly@gmail.com>: minor adjustment to docparams
- Mitar <mitar.github@tnode.com>
- Ming Lyu <CareF.Lm@gmail.com>
- Mikhail f. Shiryaev <mr.felixoid@gmail.com>
- Mike Fiedler <miketheman@gmail.com> (miketheman)
- Mike Bryant <leachim@leachim.info>
- Mike Bernard <mdbernard@pm.me>
- Michka Popoff <michkapopoff@gmail.com>
- Michal Vasilek <michal@vasilek.cz>
- Michael Scott Cuthbert <cuthbert@mit.edu>
- Michael Kefeder <oss@multiwave.ch>
- Michael K <michael-k@users.noreply.github.com>
- Michael Hudson-Doyle <michael.hudson@canonical.com>
- Michael Giuffrida <mgiuffrida@users.noreply.github.com>
- Melvin Hazeleger <31448155+melvio@users.noreply.github.com>
- Meltem Kenis <meltem.kenis@plentific.com>
- Mehdi Drissi <mdrissi@hmc.edu>
- Matěj Grabovský <mgrabovs@redhat.com>
- Matthijs Blom <19817960+MatthijsBlom@users.noreply.github.com>
- Matej Spiller Muys <matej.spiller-muys@bitstamp.net>
- Matej Marušák <marusak.matej@gmail.com>
- Marzuk Rashid <mail@marzuk.io>
- Markus Siebenhaar <41283549+siehar@users.noreply.github.com>
- Marco Edward Gorelli <marcogorelli@protonmail.com>: Documented Jupyter integration
- Marcin Kurczewski <rr-@sakuya.pl> (rr-)
- Maik Röder <maikroeder@gmail.com>
- Lumír 'Frenzy' Balhar <frenzy.madness@gmail.com>
- Ludovic Aubry <ludal@logilab.fr>
- Louis Sautier <sautier.louis@gmail.com>
- Lorena Buciu <46202743+lorena-b@users.noreply.github.com>
- Logan Miller <14319179+komodo472@users.noreply.github.com>
- Kári Tristan Helgason <kthelgason@gmail.com>
- Kurian Benoy <70306694+kurianbenoy-aot@users.noreply.github.com>
- Krzysztof Czapla <k.czapla68@gmail.com>
- Kraig Brockschmidt <kraigbr@msn.com>
- Kound <norman.freudenberg@posteo.de>
- KotlinIsland <65446343+KotlinIsland@users.noreply.github.com>
- Kosarchuk Sergey <sergeykosarchuk@gmail.com>
- Konrad Weihmann <46938494+priv-kweihmann@users.noreply.github.com>
- Kian Meng, Ang <kianmeng.ang@gmail.com>
- Kevin Phillips <thefriendlycoder@gmail.com>
- Kevin Jing Qiu <kevin.jing.qiu@gmail.com>
- Kenneth Schackart <schackartk1@gmail.com>
- Kayran Schmidt <59456929+yumasheta@users.noreply.github.com>
- Karthik Nadig <kanadig@microsoft.com>
- Jürgen Hermann <jh@web.de>
- Josselin Feist <josselin@trailofbits.com>
- Jonathan Kotta <KottaJonathan@JohnDeere.com>
- John Paraskevopoulos <io.paraskev@gmail.com>: add 'differing-param-doc' and 'differing-type-doc'
- John McGehee <jmcgehee@altera.com>
- John Gabriele <jgabriele@fastmail.fm>
- John Belmonte <john@neggie.net>
- Johannes Maron <johannes@maron.family>
- Joffrey Mander <joffrey.mander+pro@gmail.com>
- Jochen Preusche <iilei@users.noreply.github.com>
- Jeroen Seegers <jeroenseegers@users.noreply.github.com>:
* Fixed `toml` dependency issue
- Jeremy Fleischman <jeremyfleischman@gmail.com>
- Jason Owen <jason.a.owen@gmail.com>
- Jason Lau <github.com@dotkr.nl>
- Jared Garst <cultofjared@gmail.com>
- Jared Deckard <jared.deckard@gmail.com>
- Janne Rönkkö <jannero@users.noreply.github.com>
- Jamie Scott <jamie@jami.org.uk>
- James Sinclair <james@nurfherder.com>
- James M. Allen <james.m.allen@gmail.com>
- James Lingard <jchl@aristanetworks.com>
- James Broadhead <jamesbroadhead@gmail.com>
- Jakub Kulík <Kulikjak@gmail.com>
- Jakob Normark <jakobnormark@gmail.com>
- Jacques Kvam <jwkvam@gmail.com>
- Jace Browning <jacebrowning@gmail.com>: updated default report format with clickable paths
- JZ <jzohrab@gmail.com>
- JT Olds <jtolds@xnet5.com>
- Iggy Eom <iggy.eom@sendbird.com>
- Ige-kun <178478713+Ige-kun@users.noreply.github.com>
- Hayden Richards <62866982+SupImDos@users.noreply.github.com>
* Fixed "no-self-use" for async methods
* Fixed "docparams" extension for async functions and methods
- Harshil <37377066+harshil21@users.noreply.github.com>
- Harry <harrymcwinters@gmail.com>
- Gwanbin Park <bgb1028@gmail.com>
- Grégoire <96051754+gregoire-mullvad@users.noreply.github.com>
- Grant Welch <gwelch925+github@gmail.com>
- Giuseppe Valente <gvalente@arista.com>
- Gary Tyler McLeod <mail@garytyler.com>
- Felix von Drigalski <FvDrigalski@gmail.com>
- Felix Preuschoff <37065638+felixp98@users.noreply.github.com>
- Fabrice Douchant <Fabrice.Douchant@logilab.fr>
- Fabio Natali <me@fabionatali.com>
- Fabian Damken <fdamken+github@frisp.org>
- Eric Froemling <ericfroemling@gmail.com>
- Emmanuel Chaudron <manu.chaud@hotmail.fr>
- Elizabeth Bott <52465744+elizabethbott@users.noreply.github.com>
- Ekin Dursun <ekindursun@gmail.com>
- Eisuke Kawashima <e-kwsm@users.noreply.github.com>
- Edgemaster <grand.edgemaster@gmail.com>
- Eddie Darling <eddie.darling@genapsys.com>
- Drew Risinger <drewrisinger@users.noreply.github.com>
- Dr. Nick <das-intensity@users.noreply.github.com>
- Don Kirkby <donkirkby@users.noreply.github.com>
- Don Jayamanne <don.jayamanne@yahoo.com>
- Dominic Lavery <che@thisdevice.co.uk>
- Dmytro Kyrychuk <dmytro.kyrychuck@gmail.com>
- Dionisio E Alonso <baco@users.noreply.github.com>
- DetachHead <57028336+DetachHead@users.noreply.github.com>
- Dennis Keck <26092524+fellhorn@users.noreply.github.com>
- Denis Laxalde <denis.laxalde@logilab.fr>
- David Lawson <dmrlawson@gmail.com>
- David Cain <davidjosephcain@gmail.com>
- Danny Hermes <daniel.j.hermes@gmail.com>
- Daniele Procida <daniele@vurt.org>
- Daniela Plascencia <daplascen@gmail.com>
- Daniel Werner <daniel.werner@scalableminds.com>
- Daniel R. Neal <dan.r.neal@gmail.com> (danrneal)
- Daniel Draper <Germandrummer92@users.noreply.github.com>
- Daniel Dorani <ddandd@gmail.com> (doranid)
- Daniel Brookman <53625739+dbrookman@users.noreply.github.com>
- Dan Garrette <dhgarrette@gmail.com>
- Damien Nozay <damien.nozay@gmail.com>
- Cubicpath <Cubicpath@protonmail.com>
- Craig Citro <craigcitro@gmail.com>
- Cosmo <cosmo@cosmo.red>
- Clément Schreiner <clement@mux.me>
- Clément Pit-Claudel <cpitclaudel@users.noreply.github.com>
- Christopher Zurcher <zurcher@users.noreply.github.com>
- ChandanChainani <chandan.chainani@ibm.com>
- Carl Crowder <bitbucket@carlcrowder.com>: don't evaluate the value of arguments for 'dangerous-default-value'
- Carey Metcalfe <carey@cmetcalfe.ca>: demoted `try-except-raise` from error to warning
- Cameron Olechowski <camsterole@users.noreply.github.com>
- Calin Don <calin.don@gmail.com>
- Caio Carrara <ccarrara@redhat.com>
- C.A.M. Gerlach <WIDEnetServices@gmail.com>
- Bruno P. Kinoshita <kinow@users.noreply.github.com>
- Brice Chardin <brice.chardin@gmail.com>
- Brian C. Lane <bcl@redhat.com>
- Brandon W Maister <quodlibetor@gmail.com>
- BioGeek <jeroen.vangoey@gmail.com>
- Berker ŞAL <brkr.sal@gmail.com>
- Benjamin Partzsch <32679788+bnjmnp@users.noreply.github.com>
- Benjamin Graham <benwilliamgraham@gmail.com>
- Benedikt Morbach <benedikt.morbach@googlemail.com>
- Ben Greiner <code@bnavigator.de>
- Barak Shoshany <baraksh@gmail.com>
- Banjamin Freeman <befreeman@users.noreply.github.com>
- Ayushi Kotiyal <70513726+Ayushikotiyal@users.noreply.github.com>
- Avram Lubkin <avylove@rockhopper.net>
- Athos Ribeiro <athoscr@fedoraproject.org>: Fixed dict-keys-not-iterating false positive for inverse containment checks
- Arun Persaud <arun@nubati.net>
- Arthur Lutz <arthur.lutz@logilab.fr>
- Antonio Ossa <aaossa@uc.cl>
- Antonio Gámiz Delgado <73933988+antoniogamizbadger@users.noreply.github.com>
- Anthony VEREZ <anthony.verez.external@cassidian.com>
- Anthony Tan <tanant@users.noreply.github.com>
- Anthony Foglia <afoglia@users.noreply.github.com> (Google): Added simple string slots check.
- Anentropic <ego@anentropic.com>
- Andy Young <a7young@ucsd.edu>
- Andy Palmer <25123779+ninezerozeronine@users.noreply.github.com>
- Andrzej Klajnert <github@aklajnert.pl>
- Andrew Howe <howeaj@users.noreply.github.com>
- Andres Perez Hortal <andresperezcba@gmail.com>
- Andre Hora <andrehora@users.noreply.github.com>
- Aman Salwan <121633121+AmanSal1@users.noreply.github.com>
- Alok Singh <8325708+alok@users.noreply.github.com>
- Allan Chandler <95424144+allanc65@users.noreply.github.com> (allanc65)
* Fixed issue 5452, false positive missing-param-doc for multi-line Google-style params
- Alex Waygood <alex.waygood@gmail.com>
- Alex Mor <5476113+nashcontrol@users.noreply.github.com>
- Alex Jurkiewicz <alex@jurkiewi.cz>
- Alex Hearn <alex.d.hearn@gmail.com>
- Alex Fortin <alex.antoine.fortin@gmail.com>
- Aleksander Mamla <alek.mamla@gmail.com>
- Alan Evangelista <alanoe@linux.vnet.ibm.com>
- Alan Chan <achan961117@gmail.com>
- Aivar Annamaa <aivarannamaa@users.noreply.github.com>
- Aidan Haase <44787650+haasea@users.noreply.github.com>
- Ahirnish Pareek <ahirnish@gmail.com>: 'keyword-arg-before-var-arg' check
- Agustin Marquez <agusdmb@gmail.com>
- Adrian Chirieac <chirieacam@gmail.com>
- Aditya Gupta <adityagupta1089@users.noreply.github.com> (adityagupta1089)
* Added ignore_signatures to duplicate checker
- Adam Tuft <73994535+adamtuft@users.noreply.github.com>
- Adam Dangoor <adamdangoor@gmail.com>
- 243f6a88 85a308d3 <33170174+243f6a8885a308d313198a2e037@users.noreply.github.com>
Co-Author
---------
The following persons were credited manually but did not commit themselves
under this name, or we did not manage to find their commits in the history.
- Agustin Toledo
- Amaury Forgeot d'Arc: check names imported from a module exists in the module
- Anthony Tan
- Axel Muller
- Benjamin Niemann: allow block level enabling/disabling of messages
- Bernard Nauwelaerts
- Bill Wendling
- Brian van den Broek: windows installation documentation
- Craig Henriques
- D. Alphus (Alphadelta14)
- Daniil Kharkov
- Eero Vuojolahti
- Fabio Zadrozny
- Gauthier Sebaux
- James DesLauriers
- manderj
- Mirko Friedenhagen
- Nicholas Smith
- Nuzula H. Yudaka (Nuzhuka)
- Pek Chhan
- Peter Hammond
- Pierre Rouleau
- Richard Goodman: simplifiable-if-expression (with Tomer Chachamu)
- Sebastian Ulrich
- Takashi Hirashima
- Thomas Snowden: fix missing-docstring for inner functions
- Wolfgang Grafen
- Yannick Brehon

@ -1,340 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

@ -1,14 +0,0 @@
include README.rst
include requirements_test_min.txt
include requirements_test_pre_commit.txt
include requirements_test.txt
include tox.ini
graft doc
graft examples
graft script
graft tests
prune doc/_build
prune tests/.benchmarks
prune tests/.pylint_primer_tests
global-exclude __pycache__
global-exclude *.py[co]

@ -1,225 +0,0 @@
`Pylint`_
=========
.. _`Pylint`: https://pylint.readthedocs.io/
.. This is used inside the doc to recover the start of the introduction
.. image:: https://github.com/pylint-dev/pylint/actions/workflows/tests.yaml/badge.svg?branch=main
:target: https://github.com/pylint-dev/pylint/actions
.. image:: https://codecov.io/gh/pylint-dev/pylint/branch/main/graph/badge.svg?token=ZETEzayrfk
:target: https://codecov.io/gh/pylint-dev/pylint
.. image:: https://img.shields.io/pypi/v/pylint.svg
:alt: PyPI Package version
:target: https://pypi.python.org/pypi/pylint
.. image:: https://readthedocs.org/projects/pylint/badge/?version=latest
:target: https://pylint.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
:target: https://github.com/ambv/black
.. image:: https://img.shields.io/badge/linting-pylint-yellowgreen
:target: https://github.com/pylint-dev/pylint
.. image:: https://results.pre-commit.ci/badge/github/pylint-dev/pylint/main.svg
:target: https://results.pre-commit.ci/latest/github/pylint-dev/pylint/main
:alt: pre-commit.ci status
.. image:: https://bestpractices.coreinfrastructure.org/projects/6328/badge
:target: https://bestpractices.coreinfrastructure.org/projects/6328
:alt: CII Best Practices
.. image:: https://img.shields.io/ossf-scorecard/github.com/PyCQA/pylint?label=openssf%20scorecard&style=flat
:target: https://api.securityscorecards.dev/projects/github.com/PyCQA/pylint
:alt: OpenSSF Scorecard
.. image:: https://img.shields.io/discord/825463413634891776.svg
:target: https://discord.gg/qYxpadCgkx
:alt: Discord
What is Pylint?
---------------
Pylint is a `static code analyser`_ for Python 2 or 3. The latest version supports Python
3.10.0 and above.
.. _`static code analyser`: https://en.wikipedia.org/wiki/Static_code_analysis
Pylint analyses your code without actually running it. It checks for errors, enforces a
coding standard, looks for `code smells`_, and can make suggestions about how the code
could be refactored.
.. _`code smells`: https://martinfowler.com/bliki/CodeSmell.html
Install
-------
.. This is used inside the doc to recover the start of the short text for installation
For command line use, pylint is installed with::
pip install pylint
Or if you want to also check spelling with ``enchant`` (you might need to
`install the enchant C library <https://pyenchant.github.io/pyenchant/install.html#installing-the-enchant-c-library>`_):
.. code-block:: sh
pip install pylint[spelling]
It can also be integrated in most editors or IDEs. More information can be found
`in the documentation`_.
.. _in the documentation: https://pylint.readthedocs.io/en/latest/user_guide/installation/index.html
.. This is used inside the doc to recover the end of the short text for installation
What differentiates Pylint?
---------------------------
Pylint is not trusting your typing and is inferring the actual values of nodes (for a
start because there was no typing when pylint started off) using its internal code
representation (astroid). If your code is ``import logging as argparse``, Pylint
can check and know that ``argparse.error(...)`` is in fact a logging call and not an
argparse call. This makes pylint slower, but it also lets pylint find more issues if
your code is not fully typed.
[inference] is the killer feature that keeps us using [pylint] in our project despite how painfully slow it is.
- `Realist pylint user`_, 2022
.. _`Realist pylint user`: https://github.com/charliermarsh/ruff/issues/970#issuecomment-1381067064
pylint, not afraid of being a little slower than it already is, is also a lot more thorough than other linters.
There are more checks, including some opinionated ones that are deactivated by default
but can be enabled using configuration.
How to use pylint
-----------------
Pylint isn't smarter than you: it may warn you about things that you have
conscientiously done or check for some things that you don't care about.
During adoption, especially in a legacy project where pylint was never enforced,
it's best to start with the ``--errors-only`` flag, then disable
convention and refactor messages with ``--disable=C,R`` and progressively
re-evaluate and re-enable messages as your priorities evolve.
Pylint is highly configurable and permits to write plugins in order to add your
own checks (for example, for internal libraries or an internal rule). Pylint also has an
ecosystem of existing plugins for popular frameworks and third-party libraries.
.. note::
Pylint supports the Python standard library out of the box. Third-party
libraries are not always supported, so a plugin might be needed. A good place
to start is ``PyPI`` which often returns a plugin by searching for
``pylint <library>``. `pylint-pydantic`_, `pylint-django`_ and
`pylint-sonarjson`_ are examples of such plugins. More information about plugins
and how to load them can be found at `plugins`_.
.. _`plugins`: https://pylint.readthedocs.io/en/latest/development_guide/how_tos/plugins.html#plugins
.. _`pylint-pydantic`: https://pypi.org/project/pylint-pydantic
.. _`pylint-django`: https://github.com/pylint-dev/pylint-django
.. _`pylint-sonarjson`: https://github.com/cnescatlab/pylint-sonarjson-catlab
Advised linters alongside pylint
--------------------------------
Projects that you might want to use alongside pylint include ruff_ (**really** fast,
with builtin auto-fix and a large number of checks taken from popular linters, but
implemented in ``rust``) or flake8_ (a framework to implement your own checks in python using ``ast`` directly),
mypy_, pyright_ / pylance or pyre_ (typing checks), bandit_ (security oriented checks), black_ and
isort_ (auto-formatting), autoflake_ (automated removal of unused imports or variables), pyupgrade_
(automated upgrade to newer python syntax) and pydocstringformatter_ (automated pep257).
.. _ruff: https://github.com/astral-sh/ruff
.. _flake8: https://github.com/PyCQA/flake8
.. _bandit: https://github.com/PyCQA/bandit
.. _mypy: https://github.com/python/mypy
.. _pyright: https://github.com/microsoft/pyright
.. _pyre: https://github.com/facebook/pyre-check
.. _black: https://github.com/psf/black
.. _autoflake: https://github.com/myint/autoflake
.. _pyupgrade: https://github.com/asottile/pyupgrade
.. _pydocstringformatter: https://github.com/DanielNoord/pydocstringformatter
.. _isort: https://pycqa.github.io/isort/
Additional tools included in pylint
-----------------------------------
Pylint ships with two additional tools:
- pyreverse_ (standalone tool that generates package and class diagrams.)
- symilar_ (duplicate code finder that is also integrated in pylint)
.. _pyreverse: https://pylint.readthedocs.io/en/latest/additional_tools/pyreverse/index.html
.. _symilar: https://pylint.readthedocs.io/en/latest/additional_tools/symilar/index.html
.. This is used inside the doc to recover the end of the introduction
Contributing
------------
.. This is used inside the doc to recover the start of the short text for contribution
We welcome all forms of contributions such as updates for documentation, new code, checking issues for duplicates or telling us
that we can close them, confirming that issues still exist, `creating issues because
you found a bug or want a feature`_, etc. Everything is much appreciated!
Please follow the `code of conduct`_ and check `the Contributor Guides`_ if you want to
make a code contribution.
.. _creating issues because you found a bug or want a feature: https://pylint.readthedocs.io/en/latest/contact.html#bug-reports-feedback
.. _code of conduct: https://github.com/pylint-dev/pylint/blob/main/CODE_OF_CONDUCT.md
.. _the Contributor Guides: https://pylint.readthedocs.io/en/latest/development_guide/contribute.html
.. This is used inside the doc to recover the end of the short text for contribution
Show your usage
-----------------
You can place this badge in your README to let others know your project uses pylint.
.. image:: https://img.shields.io/badge/linting-pylint-yellowgreen
:target: https://github.com/pylint-dev/pylint
Learn how to add a badge to your documentation in `the badge documentation`_.
.. _the badge documentation: https://pylint.readthedocs.io/en/latest/user_guide/installation/badge.html
License
-------
pylint is, with a few exceptions listed below, `GPLv2 <https://github.com/pylint-dev/pylint/blob/main/LICENSE>`_.
The icon files are licensed under the `CC BY-SA 4.0 <https://creativecommons.org/licenses/by-sa/4.0/>`_ license:
- `doc/logo.png <https://raw.githubusercontent.com/pylint-dev/pylint/main/doc/logo.png>`_
- `doc/logo.svg <https://raw.githubusercontent.com/pylint-dev/pylint/main/doc/logo.svg>`_
Support
-------
Please check `the contact information`_.
.. _`the contact information`: https://pylint.readthedocs.io/en/latest/contact.html
.. |tideliftlogo| image:: https://raw.githubusercontent.com/pylint-dev/pylint/main/doc/media/Tidelift_Logos_RGB_Tidelift_Shorthand_On-White.png
:width: 200
:alt: Tidelift
.. list-table::
:widths: 10 100
* - |tideliftlogo|
- Professional support for pylint is available as part of the `Tidelift
Subscription`_. Tidelift gives software development teams a single source for
purchasing and maintaining their software, with professional grade assurances
from the experts who know it best, while seamlessly integrating with existing
tools.
.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-pylint?utm_source=pypi-pylint&utm_medium=referral&utm_campaign=readme

@ -1,10 +0,0 @@
coverage:
status:
patch:
default:
target: 100%
project:
default:
target: 95%
comment:
layout: "reach, diff, flags, files"

@ -1,396 +0,0 @@
abc
abcmeta
abspath
abstractproperty
analyse
analysed
analysing
arg
argparse
args
argumentdefaultshelpformatter
argumentparser
argumentsparser
argv
ascii
asend
assignattr
assignname
AST
ast
astroid
async
asynccontextmanager
attr
attrib
attrname
backport
BaseChecker
basename
behaviour
bidi
Bitbucket
bla
bom
bool
boolean
booleaness
boolop
boundmethod
builtins
bw
callables
cardinality
cd
cfg
changelog
cheaders
chroot
chunker
classdef
classdiagram
classmethod
classmethod's
classname
classobj
CLI
cls
cmp
codebase
codec
codecs
col's
conf
config
const
Const
contextlib
contextmanager
contravariance
contravariant
cgroup
CPython
cpython
csv
CVE
cwd
cyclomatic
dataclass
dataclasses
datetime
debian
deduplication
deepcopy
defaultdicts
defframe
defstmts
deleter
dependabot
deque
destructured
destructuring
diadefs
diadefslib
dictcomp
dicts
dir
dirname
docparams
docstring
docstrings
dumpable
dunder
elif
elif's
elt
emittable
encodings
endswith
enum
enums
epilog
epylint
epytext
erroring
etree
expr
falsey
favour
filepath
filestream
finalbody
# TODO Remove when we are able to remove our own symbols
fixme
Flymake
fmt
formatter
formfeed
fromlineno
fullname
func
functiondef
functiøn
functools
genexpr
getattr
globals
globbing
GPL
graphname
graphviz
grey
guido's
gv
hashable
hmac
html
idgeneratormixin
ifexpr
igetattr
importedname
importfrom
importnode
importschecker
InferenceError
ini
INI
init
initializer
inlinevar
instantiation
isdir
isfile
isinstance
isort
iter
iterable
iterables
itered
iteritems
iTerm
jn
jpg
json
jx
jython
# class is a reserved word
klass
kwarg
kwargs
kwonlyargs
latin
len
lhs
linecache
lineno
linenum
lineset
lineset's
linesets
linkers
linter
linux
listcomp
Logilab
longstring
lsp
mapfile
mapreduce
maxsize
maxsplit
mcs
mermaidjs
metaclass
metaclasses
misdesign
misdesigns
mixin
modname
monkeypatch
mro
# Used so much that we need the abbreviation
msg
msg-template
msgid
msgids
msgs
mult
multiline
multiset
multisets
myattr
myfunction
mymain
mymethod
mymodule
mypy
namedtuple
namespace
newsfile
newstyle
nl
nodename
nodeng
noinspection
nonlocal
nonlocals
num
numpy
ok
optdict
optik
optionals
optiondict
optname
optparse
optvalue
orelse
os
outputfile
overridable
params
paren
parens
passthru
pathlib
patternerror
png
positionals
pragma
pragma's
pragmas
pre
preorder
prepended
proc
py
pyenchant
pyfile
pyi
pylint
pylint's
pylintdict
pylintrc
pyproject
pypy
pyreverse
pytest
qname
rawcheckers
rc
rcfile
re-usable
readlines
recognise
recurse
recurses
redef
reportid
rgx
rheaders
rhs
roid
rsplit
rst
rstrip
rtype
runtime
se
seaborn
sep
setcomp
shortstrings
singledispatch
singledispatchmethod
spammy
sqlalchemy
src
starargs
stateful
staticmethod
stderr
stdin
stdlib
stdout
stmt
str
stringified
subclasses
subcommands
subdicts
subgraphs
sublists
submodule
submodules
subparsers
subparts
subprocess
subscriptable
subscripted
subtree
supcls
superclass
symilar
symlink
symlinks
sys
tbump
tempfile
testcase
testdata
testoptions
tmp
tokencheckers
tokeninfo
tokenization
tokenize
tokenizer
toml
tomlkit
toplevel
towncrier
tp
truthey
truthness
truthy
tryexcept
txt
typecheck
typechecking
typeddict
typehint
typeshed
uid
uml
un
unary
unflattens
unhandled
unicode
uninferable
Uninferable
unittest
unraisablehook
untriggered
# prefix for string
ur
ureport
ureports
utf
utils
validator
vararg
varargs
variadic
variadics
vcg
vcg's
vectorisation
virtualized
wc
whitespaces
xfails
xml
xyz
yml
yoda

@ -1,47 +0,0 @@
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
# --------------------------------
# This part is specific to pylint.
#---------------------------------
# Set PYLINT_SPHINX_FATAL_WARNINGS= on the command line to restore the default.
PYLINT_SPHINX_FATAL_WARNINGS = -W --keep-going
# Do not use O, we abuse it for internal purposes.
O = -d $(BUILDDIR)/doctrees -T $(PYLINT_SPHINX_FATAL_WARNINGS) -n
.PHONY clean: remove-generated-messages
remove-generated-messages:
rm -rf user_guide/messages/convention user_guide/messages/error \
user_guide/messages/fatal user_guide/messages/information user_guide/messages/refactor \
user_guide/messages/warning
# Generated by exts/*.py but kept in the VCS for easier review of changes:
.PHONY: distclean
distclean: clean
rm -f user_guide/checkers/extensions.rst user_guide/checkers/features.rst \
user_guide/configuration/all-options.rst user_guide/messages/messages_overview.rst
# Set PIP=true on the command line to skip installation of dependencies.
PIP = pip
.PHONY html: install-dependencies
install-dependencies:
@echo "Install dependencies"
cd ../ && $(PIP) install -r doc/requirements.txt

@ -1,201 +0,0 @@
.. This file is auto-generated. Make any changes to the associated
.. docs extension in 'doc/exts/pyreverse_configuration.py'.
Usage
#####
``pyreverse`` is run from the command line using the following syntax::
pyreverse [options] <packages>
where ``<packages>`` is one or more Python packages or modules to analyze.
The available options are organized into the following categories:
* :ref:`filtering-and-scope` - Control which classes and relationships appear in your diagrams
* :ref:`display-options` - Customize the visual appearance including colors and labels
* :ref:`output-control` - Select output formats and set the destination directory
* :ref:`project-configuration` - Define project settings like source roots and ignored files
.. _filtering-and-scope:
Filtering and Scope
===================
--all-ancestors
---------------
*Show all ancestors of all classes in <projects>.*
**Default:** ``None``
--all-associated
----------------
*Show all classes associated with the target classes, including indirect associations.*
**Default:** ``None``
--class
-------
*Create a class diagram with all classes related to <class>; this uses by default the options -ASmy*
**Default:** ``None``
--filter-mode
-------------
*Filter attributes and functions according to <mode>. Correct modes are:
'PUB_ONLY' filter all non public attributes [DEFAULT], equivalent to PRIVATE+SPECIAL
'ALL' no filter
'SPECIAL' filter Python special functions except constructor
'OTHER' filter protected and private attributes*
**Default:** ``PUB_ONLY``
--max-depth
-----------
*Maximum depth of packages/modules to include in the diagram, relative to the deepest specified package. A depth of 0 shows only the specified packages/modules, while 1 includes their immediate children, etc. When specifying nested packages, depth is calculated from the deepest package level. If not specified, all packages/modules in the hierarchy are shown.*
**Default:** ``None``
--show-ancestors
----------------
*Show <ancestor> generations of ancestor classes not in <projects>.*
**Default:** ``None``
--show-associated
-----------------
*Show <association_level> levels of associated classes not in <projects>.*
**Default:** ``None``
--show-builtin
--------------
*Include builtin objects in representation of classes.*
**Default:** ``False``
--show-stdlib
-------------
*Include standard library objects in representation of classes.*
**Default:** ``False``
.. _display-options:
Display Options
===============
--color-palette
---------------
*Comma separated list of colors to use for the package depth coloring.*
**Default:** ``('#77AADD', '#99DDFF', '#44BB99', '#BBCC33', '#AAAA00', '#EEDD88', '#EE8866', '#FFAABB', '#DDDDDD')``
--colorized
-----------
*Use colored output. Classes/modules of the same package get the same color.*
**Default:** ``False``
--max-color-depth
-----------------
*Use separate colors up to package depth of <depth>. Higher depths will reuse colors.*
**Default:** ``2``
--module-names
--------------
*Include module name in the representation of classes.*
**Default:** ``None``
--no-standalone
---------------
*Only show nodes with connections.*
**Default:** ``False``
--only-classnames
-----------------
*Don't show attributes and methods in the class boxes; this disables -f values.*
**Default:** ``False``
.. _output-control:
Output Control
==============
--output
--------
*Create a *.<format> output file if format is available. Available formats are: .dot, .puml, .plantuml, .mmd, .html. Any other format will be tried to be created by using the 'dot' command line tool, which requires a graphviz installation. In this case, these additional formats are available (see `Graphviz output formats <https://graphviz.org/docs/outputs/>`_).*
**Default:** ``dot``
--output-directory
------------------
*Set the output directory path.*
**Default:** ``""``
.. _project-configuration:
Project Configuration
=====================
--ignore
--------
*Files or directories to be skipped. They should be base names, not paths.*
**Default:** ``('CVS',)``
--project
---------
*Set the project name. This will later be appended to the output file names.*
**Default:** ``""``
--source-roots
--------------
*Add paths to the list of the source roots. Supports globbing patterns. The source root is an absolute path or a path relative to the current working directory used to determine a package namespace for modules located under the source root.*
**Default:** ``()``
--verbose
---------
*Makes pyreverse more verbose/talkative. Mostly useful for debugging.*
**Default:** ``False``

@ -1,40 +0,0 @@
.. _pyreverse:
=========
Pyreverse
=========
``pyreverse`` is a powerful tool that creates UML diagrams from your Python code. It helps you visualize:
- Package dependencies and structure
- Class hierarchies and relationships
- Method and attribute organization
Output Formats
==============
``pyreverse`` supports multiple output formats:
* Native formats:
* ``.dot``/``.gv`` (Graphviz)
* ``.puml``/``.plantuml`` (PlantUML)
* ``.mmd``/``.html`` (MermaidJS)
* Additional formats (requires Graphviz installation):
* All `Graphviz output formats <https://graphviz.org/docs/outputs/>`_ (PNG, SVG, PDF, etc.)
* ``pyreverse`` first generates a temporary ``.gv`` file, which is then fed to Graphviz to generate the final image
Getting Started
===============
Check out the :doc:`configuration` guide to learn about available options, or see :doc:`output_examples`
for sample diagrams and common use cases.
.. toctree::
:maxdepth: 2
:caption: Pyreverse
:titlesonly:
:hidden:
configuration
output_examples

@ -1,40 +0,0 @@
Example Output
##############
Example diagrams generated with the ``.puml`` output format are shown below.
Package Diagram
...............
.. image:: ../../media/pyreverse_example_packages.png
:width: 344
:height: 177
:alt: Package diagram generated by pyreverse
:align: center
Class Diagram
.............
.. image:: ../../media/pyreverse_example_classes.png
:width: 625
:height: 589
:alt: Class diagram generated by pyreverse
:align: center
Creating Class Diagrams for Specific Classes
''''''''''''''''''''''''''''''''''''''''''''
In many cases creating a single diagram depicting all classes in the project yields a rather unwieldy, giant diagram.
While limiting the input path to a single package or module can already help greatly to narrow down the scope, the ``-c`` option
provides another way to create a class diagram focusing on a single class and its collaborators.
For example, running::
pyreverse -ASmy -c pylint.checkers.classes.ClassChecker pylint
will generate the full class and package diagrams for ``pylint``, but will additionally generate a file ``pylint.checkers.classes.ClassChecker.dot``:
.. image:: ../../media/ClassChecker_diagram.png
:width: 757
:height: 1452
:alt: Package diagram generated by pyreverse
:align: center

@ -1,37 +0,0 @@
.. _symilar:
Symilar
-------
The console script ``symilar`` finds copy pasted block of text in a set of files. It provides a command line interface to check only the ``duplicate-code`` message.
It can be invoked with::
symilar [-d|--duplicates min_duplicated_lines] [-i|--ignore-comments] [--ignore-docstrings] [--ignore-imports] [--ignore-signatures] file1...
All files that shall be checked have to be passed in explicitly, e.g.::
symilar foo.py, bar.py, subpackage/spam.py, subpackage/eggs.py
``symilar`` produces output like the following::
17 similar lines in 2 files
==tests/data/clientmodule_test.py:3
==tests/data/suppliermodule_test.py:12
class Ancestor:
""" Ancestor method """
cls_member = DoNothing()
def __init__(self, value):
local_variable = 0
self.attr = 'this method shouldn\'t have a docstring'
self.__value = value
def get_value(self):
""" nice docstring ;-) """
return self.__value
def set_value(self, value):
self.__value = value
return 'this method shouldn\'t have a docstring'
TOTAL lines=58 duplicates=17 percent=29.31

@ -1,310 +0,0 @@
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# For details: https://github.com/pylint-dev/pylint/blob/main/LICENSE
# Copyright (c) https://github.com/pylint-dev/pylint/blob/main/CONTRIBUTORS.txt
from __future__ import annotations
import os
import sys
from datetime import datetime
# Pylint documentation build configuration file, created by
# sphinx-quickstart on Thu Apr 4 20:31:25 2013.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use 'os.path.abspath' to make it absolute, like shown here.
sys.path.append(os.path.abspath("exts"))
sys.path.append(os.path.abspath(".."))
# pylint: disable=wrong-import-position
from pylint import __version__
from pylint.__pkginfo__ import numversion
# pylint: enable=wrong-import-position
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [
"pylint_features",
"pylint_extensions",
"pylint_messages",
"pylint_options",
"pyreverse_configuration",
"sphinx.ext.autosectionlabel",
"sphinx.ext.intersphinx",
"sphinx_reredirects",
]
# Single file redirects are handled in this file and can be done by a pylint
# contributor. We use the following extension:
# https://documatt.gitlab.io/sphinx-reredirects/usage.html
# Directory redirects are handled in ReadTheDoc admin interface and can only be done
# by pylint maintainers at the following URL:
# https://readthedocs.org/dashboard/pylint/redirects/
redirects: dict[str, str] = {
# "<source>": "<target>"
"additional_commands/index": "../index.html",
"development_guide/index": "api/index.html",
"development_guide/contribute": "../development_guide/contributor_guide/index.html",
"development_guide/contributor_guide": "contributor_guide/index.html",
"development_guide/profiling": "../development_guide/contributor_guide/profiling.html",
"development_guide/tests/index": "../contributor_guide/tests/index.html",
"development_guide/tests/install": "../contributor_guide/tests/install.html",
"development_guide/tests/launching_test": "../contributor_guide/tests/launching_test.html",
# There was a typo in the original file, don't fix.
"development_guide/tests/writting_test": "../contributor_guide/tests/writing_test.html",
"development/testing": "tests/index.html",
"how_tos/custom_checkers": "../development_guide/how_tos/custom_checkers.html",
"how_tos/index": "../development_guide/how_tos/index.html",
"how_tos/plugins": "../development_guide/how_tos/plugins.html",
"how_tos/transform_plugins": "../development_guide/how_tos/transform_plugins.html",
"intro": "index.html",
"messages/messages_introduction": "../user_guide/messages/index.html",
"messages/messages_list": "../user_guide/messages/messages_overview.html",
"support": "contact.html",
"technical_reference/c_extensions": "../user_guide/messages/error/no-member.html",
"technical_reference/extensions": "../user_guide/checkers/extensions.html",
"technical_reference/checkers": "../development_guide/technical_reference/checkers.html",
"technical_reference/features": "../user_guide/checkers/features.html",
"technical_reference/index": "../development_guide/technical_reference/index.html",
"technical_reference/startup": "../development_guide/technical_reference/startup.html",
"user_guide/configuration/naming-styles": "../user_guide/messages/convention/invalid-name.html",
"user_guide/ide_integration/flymake-emacs": "../installation/ide_integration/flymake-emacs.html",
"user_guide/ide_integration/ide-integration": "../installation/ide_integration/index.html",
"user_guide/ide-integration": "installation.html",
"user_guide/ide_integration/textmate": "../installation/ide_integration/textmate.html",
"user_guide/index": "installation/index.html",
"user_guide/message-control": "messages/message_control.html",
"user_guide/options": "configuration/all-options.html",
"user_guide/output": "usage/output.html",
"user_guide/pre-commit-integration": "installation/pre-commit-integration.html",
"user_guide/run": "usage/run.html",
"pyreverse": "additional_tools/pyreverse/index.html",
"symilar": "additional_tools/symilar/index.html",
}
# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]
# The suffix of source filenames.
source_suffix = ".rst"
# The encoding of source files.
# source_encoding = 'utf-8-sig'
# The root toctree document.
root_doc = "index"
# General information about the project.
project = "Pylint"
current_year = datetime.utcnow().year
contributors = "Logilab and Pylint contributors"
copyright = f"2003-{current_year}, {contributors}" # pylint: disable=redefined-builtin
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
# The short X.Y version.
version = f"{numversion[0]}.{numversion[1]}"
# The full version, including alpha/beta/rc tags.
release = __version__
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
# language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
# today = ''
# Else, today_fmt is used as the format for a strftime call.
# today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ["_build", "data/**", "whatsnew/fragments"]
# The reST default role (used for this markup: `text`) to use for all documents.
# default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
# add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = "sphinx"
# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = "furo"
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
# Currently we use the default Furo configuration
# html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
# html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
# html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
# html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
# html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
# html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
# html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
html_last_updated_fmt = "%b %d, %Y"
smartquotes = False
# Custom sidebar templates, maps document names to template names.
# Currently we use the default Furo Sidebar
# html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
# html_additional_pages = {}
# If false, no module index is generated.
# html_domain_indices = True
# If false, no index is generated.
# html_use_index = True
# If true, the index is split into individual pages for each letter.
# html_split_index = False
# If true, links to the reST sources are added to the pages.
html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
# html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
# html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
# html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
# html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = "Pylintdoc"
# -- Options for LaTeX output --------------------------------------------------
# The paper size ('letter' or 'a4').
# latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
# latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
(
"index",
"Pylint.tex",
"Pylint Documentation",
contributors,
"manual",
)
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
# latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
# latex_use_parts = False
# If true, show page references after internal links.
# latex_show_pagerefs = False
# If true, show URL addresses after external links.
# latex_show_urls = False
# Additional stuff for the LaTeX preamble.
# latex_preamble = ''
# Documents to append as an appendix to all manuals.
# latex_appendices = []
# If false, no module index is generated.
# latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [("index", "pylint", "Pylint Documentation", [contributors], 1)]
# pylint: disable-next=consider-using-namedtuple-or-dataclass
intersphinx_mapping = {
"astroid": ("https://pylint.readthedocs.io/projects/astroid/en/latest/", None),
"python": ("https://docs.python.org/3", None),
}
# Prevent label issues due to colliding section names
# through including multiple documents
autosectionlabel_prefix_document = True
# Permit duplicated titles in the resulting document.
# See https://github.com/pylint-dev/pylint/issues/7362#issuecomment-1256932866
autosectionlabel_maxdepth = 2
linkcheck_ignore = [
"https://github.com/pylint-dev/pylint/blob/main/pylint/extensions/.*"
]

@ -1,58 +0,0 @@
Contact
=======
Bug reports, feedback
---------------------
.. _bug reports, feedback:
You think you have found a bug in Pylint? Well, this may be the case
since Pylint and Python are under heavy development!
Please take the time to check if it is already in the issue tracker at
https://github.com/pylint-dev/pylint
Note that the issue might also be reported in one of Pylint's major dependencies,
astroid:
* https://github.com/pylint-dev/astroid
Discord server
--------------
You can discuss your problem using the discord server:
https://discord.com/invite/Egy6P8AMB5
Mailing lists
-------------
.. _Mailing lists:
The code-quality mailing list is shared with other tools that aim
at improving the quality of python code.
You can subscribe to this mailing list at
https://mail.python.org/mailman3/lists/code-quality.python.org/
Archives are available at
https://mail.python.org/pipermail/code-quality/
Archives before April 2013 are not available anymore. At
https://mail.python.org/pipermail/ it was under ``python-projects``.
Support
-------
.. image:: media/Tidelift_Logos_RGB_Tidelift_Shorthand_On-White.png
:height: 150
:alt: Tidelift
:align: left
:class: tideliftlogo
Professional support for pylint is available as part of the `Tidelift
Subscription`_. Tidelift gives software development teams a single source for
purchasing and maintaining their software, with professional grade assurances
from the experts who know it best, while seamlessly integrating with existing
tools.
.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-pylint?utm_source=pypi-pylint&utm_medium=referral&utm_campaign=readme

@ -1,10 +0,0 @@
import abc
class Animal(abc.ABC):
@abc.abstractmethod
def make_sound(self):
pass
sheep = Animal() # [abstract-class-instantiated]

@ -1,15 +0,0 @@
import abc
class Animal(abc.ABC):
@abc.abstractmethod
def make_sound(self):
pass
class Sheep(Animal):
def make_sound(self):
print("bhaaaaa")
sheep = Sheep()

@ -1,11 +0,0 @@
import abc
class WildAnimal:
@abc.abstractmethod
def make_sound(self):
pass
class Panther(WildAnimal): # [abstract-method]
pass

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save