Merge branch 'main' into storefront-nuxt
This commit is contained in:
commit
0f53ac3710
16 changed files with 811 additions and 487 deletions
|
|
@ -375,7 +375,6 @@ class BrandAdmin(DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, Mo
|
||||||
search_fields = (
|
search_fields = (
|
||||||
"uuid",
|
"uuid",
|
||||||
"name",
|
"name",
|
||||||
"categories__name",
|
|
||||||
)
|
)
|
||||||
readonly_fields = (
|
readonly_fields = (
|
||||||
"uuid",
|
"uuid",
|
||||||
|
|
@ -389,9 +388,10 @@ class BrandAdmin(DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, Mo
|
||||||
"description",
|
"description",
|
||||||
"priority",
|
"priority",
|
||||||
]
|
]
|
||||||
relation_fields = [
|
additional_fields = [
|
||||||
"categories",
|
"small_logo",
|
||||||
]
|
"big_logo"
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
@register(Product)
|
@register(Product)
|
||||||
|
|
|
||||||
28
engine/core/templates/admin/dashboard/_customers_mix.html
Normal file
28
engine/core/templates/admin/dashboard/_customers_mix.html
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
{% load i18n unfold %}
|
||||||
|
|
||||||
|
{% component "unfold/components/card.html" %}
|
||||||
|
{% component "unfold/components/title.html" %}
|
||||||
|
{% trans "Customers mix (30d)" %}
|
||||||
|
{% endcomponent %}
|
||||||
|
{% if customers_mix.total|default:0 > 0 %}
|
||||||
|
<div class="flex flex-col gap-3">
|
||||||
|
<div class="flex items-center justify-between text-sm">
|
||||||
|
<span class="text-gray-600 dark:text-gray-300">{% trans "New customers" %}</span>
|
||||||
|
<span class="font-medium">{{ customers_mix.new }} ({{ customers_mix.new_pct }}%)</span>
|
||||||
|
</div>
|
||||||
|
{% component "unfold/components/progress.html" with value=customers_mix.new_pct title='' description='' %}
|
||||||
|
{% endcomponent %}
|
||||||
|
|
||||||
|
<div class="flex items-center justify-between text-sm mt-2">
|
||||||
|
<span class="text-gray-600 dark:text-gray-300">{% trans "Returning customers" %}</span>
|
||||||
|
<span class="font-medium">{{ customers_mix.returning }} ({{ customers_mix.returning_pct }}%)</span>
|
||||||
|
</div>
|
||||||
|
{% component "unfold/components/progress.html" with value=customers_mix.returning_pct title='' description='' %}
|
||||||
|
{% endcomponent %}
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
{% component "unfold/components/text.html" %}
|
||||||
|
{% trans "No customer activity in the last 30 days." %}
|
||||||
|
{% endcomponent %}
|
||||||
|
{% endif %}
|
||||||
|
{% endcomponent %}
|
||||||
129
engine/core/templates/admin/dashboard/_daily_sales.html
Normal file
129
engine/core/templates/admin/dashboard/_daily_sales.html
Normal file
|
|
@ -0,0 +1,129 @@
|
||||||
|
{% load i18n unfold static %}
|
||||||
|
|
||||||
|
{% component "unfold/components/card.html" %}
|
||||||
|
{% component "unfold/components/title.html" %}
|
||||||
|
{% trans "Daily sales (30d)" %}
|
||||||
|
{% endcomponent %}
|
||||||
|
<div class="w-full">
|
||||||
|
<canvas id="dailySalesChart" height="120"></canvas>
|
||||||
|
</div>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
|
{{ daily_labels|json_script:"daily-labels" }}
|
||||||
|
{{ daily_orders|json_script:"daily-orders" }}
|
||||||
|
{{ daily_gross|json_script:"daily-gross" }}
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
try {
|
||||||
|
let labels = [];
|
||||||
|
let orders = [];
|
||||||
|
let gross = [];
|
||||||
|
const elL = document.getElementById('daily-labels');
|
||||||
|
const elO = document.getElementById('daily-orders');
|
||||||
|
const elG = document.getElementById('daily-gross');
|
||||||
|
if (elL && elO && elG) {
|
||||||
|
labels = JSON.parse(elL.textContent || '[]');
|
||||||
|
orders = JSON.parse(elO.textContent || '[]');
|
||||||
|
gross = JSON.parse(elG.textContent || '[]');
|
||||||
|
}
|
||||||
|
if (!labels || labels.length === 0) {
|
||||||
|
const now = new Date();
|
||||||
|
labels = [];
|
||||||
|
orders = [];
|
||||||
|
gross = [];
|
||||||
|
for (let i = 29; i >= 0; i--) {
|
||||||
|
const d = new Date(now);
|
||||||
|
d.setDate(now.getDate() - i);
|
||||||
|
const day = String(d.getDate()).padStart(2, '0');
|
||||||
|
const month = d.toLocaleString(undefined, {month: 'short'});
|
||||||
|
labels.push(`${day} ${month}`);
|
||||||
|
orders.push(0);
|
||||||
|
gross.push(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ctx = document.getElementById('dailySalesChart').getContext('2d');
|
||||||
|
const green = 'rgb(34,197,94)';
|
||||||
|
const blue = 'rgb(59,130,246)';
|
||||||
|
|
||||||
|
const currency = "{% if currency_symbol %}{{ currency_symbol }}{% endif %}";
|
||||||
|
|
||||||
|
const allZeroOrders = (orders || []).every(function (v) { return Number(v || 0) === 0; });
|
||||||
|
const allZeroGross = (gross || []).every(function (v) { return Number(v || 0) === 0; });
|
||||||
|
|
||||||
|
new Chart(ctx, {
|
||||||
|
type: 'line',
|
||||||
|
data: {
|
||||||
|
labels: labels,
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: '{{ _("Orders (FINISHED)") }}',
|
||||||
|
data: orders,
|
||||||
|
borderColor: allZeroOrders ? 'rgba(0,0,0,0)' : green,
|
||||||
|
backgroundColor: allZeroOrders ? 'rgba(0,0,0,0)' : green,
|
||||||
|
borderWidth: allZeroOrders ? 0 : 2,
|
||||||
|
tension: 0.25,
|
||||||
|
pointRadius: allZeroOrders ? 0 : 2,
|
||||||
|
yAxisID: 'yOrders',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '{{ _("Gross revenue") }}',
|
||||||
|
data: gross,
|
||||||
|
borderColor: allZeroGross ? 'rgba(0,0,0,0)' : blue,
|
||||||
|
backgroundColor: allZeroGross ? 'rgba(0,0,0,0)' : blue,
|
||||||
|
borderWidth: allZeroGross ? 0 : 2,
|
||||||
|
tension: 0.25,
|
||||||
|
pointRadius: allZeroGross ? 0 : 2,
|
||||||
|
yAxisID: 'yRevenue',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
interaction: {mode: 'index', intersect: false},
|
||||||
|
plugins: {
|
||||||
|
legend: {display: true},
|
||||||
|
tooltip: {
|
||||||
|
callbacks: {
|
||||||
|
label: function (context) {
|
||||||
|
const label = context.dataset.label || '';
|
||||||
|
const val = context.parsed.y;
|
||||||
|
if (context.dataset.yAxisID === 'yRevenue') {
|
||||||
|
return `${label}: ${currency}${val}`;
|
||||||
|
}
|
||||||
|
return `${label}: ${val}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
grid: {display: false}
|
||||||
|
},
|
||||||
|
yOrders: {
|
||||||
|
type: 'linear',
|
||||||
|
position: 'left',
|
||||||
|
title: {display: true, text: '{{ _("Orders") }}'},
|
||||||
|
grid: {color: 'rgba(0,0,0,0.06)'},
|
||||||
|
ticks: {precision: 0}
|
||||||
|
},
|
||||||
|
yRevenue: {
|
||||||
|
type: 'linear',
|
||||||
|
position: 'right',
|
||||||
|
title: {display: true, text: '{{ _("Gross") }}'},
|
||||||
|
grid: {drawOnChartArea: false},
|
||||||
|
ticks: {
|
||||||
|
callback: function (value) {
|
||||||
|
return `${currency}${value}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console && console.warn && console.warn('Chart init failed', e);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
{% endcomponent %}
|
||||||
118
engine/core/templates/admin/dashboard/_income_overview.html
Normal file
118
engine/core/templates/admin/dashboard/_income_overview.html
Normal file
|
|
@ -0,0 +1,118 @@
|
||||||
|
{% load i18n unfold arith %}
|
||||||
|
|
||||||
|
{% with gross=revenue_gross_30|default:0 returns=returns_30|default:0 %}
|
||||||
|
{% with total=gross|add:returns %}
|
||||||
|
{% component "unfold/components/card.html" with class="xl:col-span-2" %}
|
||||||
|
{% component "unfold/components/title.html" %}
|
||||||
|
{% trans "Income overview" %}
|
||||||
|
{% endcomponent %}
|
||||||
|
|
||||||
|
{% with net=revenue_net_30|default:0 %}
|
||||||
|
{% with tax_amt=gross|sub:net %}
|
||||||
|
{% with returns_capped=returns %}
|
||||||
|
{% if returns > gross %}
|
||||||
|
{% with returns_capped=gross %}{% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
{% with tax_amt_pos=tax_amt %}
|
||||||
|
{% if tax_amt_pos < 0 %}
|
||||||
|
{% with tax_amt_pos=0 %}{% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
{% with net_for_pie=gross|sub:tax_amt_pos|sub:returns_capped %}
|
||||||
|
{% if net_for_pie < 0 %}
|
||||||
|
{% with net_for_pie=0 %}{% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
<div class="flex flex-col sm:flex-row items-center gap-6">
|
||||||
|
<div class="relative w-48 h-48">
|
||||||
|
<canvas id="incomePieChart" width="192" height="192"></canvas>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="flex items-center gap-2 mb-2">
|
||||||
|
<span class="inline-block w-3 h-3 rounded-sm" style="background:rgb(34,197,94)"></span>
|
||||||
|
<span class="text-sm text-gray-600 dark:text-gray-300">{% trans "Net" %}:</span>
|
||||||
|
<span class="font-semibold">{% if currency_symbol %}{{ currency_symbol }}{% endif %}{{ net }}</span>
|
||||||
|
</div>
|
||||||
|
{% if tax_amt_pos > 0 %}
|
||||||
|
<div class="flex items-center gap-2 mb-2">
|
||||||
|
<span class="inline-block w-3 h-3 rounded-sm" style="background:rgb(249,115,22)"></span>
|
||||||
|
<span class="text-sm text-gray-600 dark:text-gray-300">{% trans "Taxes" %}:</span>
|
||||||
|
<span class="font-semibold">{% if currency_symbol %}{{ currency_symbol }}{% endif %}{{ tax_amt_pos|floatformat:2 }}</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="flex items-center gap-2 mb-2">
|
||||||
|
<span class="inline-block w-3 h-3 rounded-sm" style="background:rgb(239,68,68)"></span>
|
||||||
|
<span class="text-sm text-gray-600 dark:text-gray-300">{% trans "Returns" %}:</span>
|
||||||
|
<span class="font-semibold">{% if currency_symbol %}{{ currency_symbol }}{% endif %}{{ returns }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="inline-block w-3 h-3 rounded-sm" style="background:linear-gradient(90deg, rgba(0,0,0,0.15), rgba(0,0,0,0.15))"></span>
|
||||||
|
<span class="text-sm text-gray-600 dark:text-gray-300">{% trans "Gross (pie total)" %}:</span>
|
||||||
|
<span class="font-semibold">{% if currency_symbol %}{{ currency_symbol }}{% endif %}{{ gross }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
try {
|
||||||
|
const ctx = document.getElementById('incomePieChart').getContext('2d');
|
||||||
|
const gross = Number({{ gross|default:0 }});
|
||||||
|
const netBackend = Number({{ net|default:0 }});
|
||||||
|
const returnsRaw = Number({{ returns_capped|default:0 }});
|
||||||
|
const taxes = Math.max(gross - netBackend, 0);
|
||||||
|
const returnsVal = Math.min(returnsRaw, gross);
|
||||||
|
const netVal = Math.max(gross - taxes - returnsVal, 0);
|
||||||
|
|
||||||
|
let dataValues = [netVal, taxes, returnsVal];
|
||||||
|
let labels = ['{{ _("Net") }}', '{{ _("Taxes") }}', '{{ _("Returns") }}'];
|
||||||
|
let colors = ['rgb(34,197,94)', 'rgb(249,115,22)', 'rgb(239,68,68)'];
|
||||||
|
|
||||||
|
const sum = dataValues.reduce((a, b) => a + Number(b || 0), 0);
|
||||||
|
if (sum <= 0) {
|
||||||
|
dataValues = [1];
|
||||||
|
labels = ['{{ _("No data") }}'];
|
||||||
|
colors = ['rgba(0,0,0,0.1)'];
|
||||||
|
}
|
||||||
|
|
||||||
|
const currency = "{% if currency_symbol %}{{ currency_symbol }}{% endif %}";
|
||||||
|
new Chart(ctx, {
|
||||||
|
type: 'doughnut',
|
||||||
|
data: {
|
||||||
|
labels: labels,
|
||||||
|
datasets: [{
|
||||||
|
data: dataValues,
|
||||||
|
backgroundColor: colors,
|
||||||
|
borderWidth: 0,
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
plugins: {
|
||||||
|
legend: {position: 'bottom'},
|
||||||
|
tooltip: {
|
||||||
|
callbacks: {
|
||||||
|
label: function (context) {
|
||||||
|
const label = context.label || '';
|
||||||
|
const val = context.parsed || 0;
|
||||||
|
if (labels.length === 1) return label;
|
||||||
|
return `${label}: ${currency}${val}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
cutout: '55%'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console && console.warn && console.warn('Pie chart init failed', e);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
{% endwith %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endcomponent %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endwith %}
|
||||||
39
engine/core/templates/admin/dashboard/_kpis.html
Normal file
39
engine/core/templates/admin/dashboard/_kpis.html
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
{% load i18n unfold %}
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-4 mb-6">
|
||||||
|
{% component "unfold/components/card.html" %}
|
||||||
|
{% component "unfold/components/text.html" %}
|
||||||
|
{% trans "Revenue (gross, 30d)" %}
|
||||||
|
{% endcomponent %}
|
||||||
|
{% component "unfold/components/title.html" %}
|
||||||
|
{% if currency_symbol %}{{ currency_symbol }}{% endif %}{{ revenue_gross_30|default:0 }}
|
||||||
|
{% endcomponent %}
|
||||||
|
{% endcomponent %}
|
||||||
|
|
||||||
|
{% component "unfold/components/card.html" %}
|
||||||
|
{% component "unfold/components/text.html" %}
|
||||||
|
{% trans "Revenue (net, 30d)" %}
|
||||||
|
{% endcomponent %}
|
||||||
|
{% component "unfold/components/title.html" %}
|
||||||
|
{% if currency_symbol %}{{ currency_symbol }}{% endif %}{{ revenue_net_30|default:0 }}
|
||||||
|
{% endcomponent %}
|
||||||
|
{% endcomponent %}
|
||||||
|
|
||||||
|
{% component "unfold/components/card.html" %}
|
||||||
|
{% component "unfold/components/text.html" %}
|
||||||
|
{% trans "Returns (30d)" %}
|
||||||
|
{% endcomponent %}
|
||||||
|
{% component "unfold/components/title.html" %}
|
||||||
|
{% if currency_symbol %}{{ currency_symbol }}{% endif %}{{ returns_30|default:0 }}
|
||||||
|
{% endcomponent %}
|
||||||
|
{% endcomponent %}
|
||||||
|
|
||||||
|
{% component "unfold/components/card.html" %}
|
||||||
|
{% component "unfold/components/text.html" %}
|
||||||
|
{% trans "Processed orders (30d)" %}
|
||||||
|
{% endcomponent %}
|
||||||
|
{% component "unfold/components/title.html" %}
|
||||||
|
{{ processed_orders_30|default:0 }}
|
||||||
|
{% endcomponent %}
|
||||||
|
{% endcomponent %}
|
||||||
|
</div>
|
||||||
27
engine/core/templates/admin/dashboard/_most_returned.html
Normal file
27
engine/core/templates/admin/dashboard/_most_returned.html
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
{% load i18n unfold %}
|
||||||
|
|
||||||
|
{% component "unfold/components/card.html" %}
|
||||||
|
{% component "unfold/components/title.html" %}
|
||||||
|
{% trans "Most returned products (30d)" %}
|
||||||
|
{% endcomponent %}
|
||||||
|
{% if most_returned_products %}
|
||||||
|
<ul class="flex flex-col divide-y divide-gray-200 dark:divide-base-700/50">
|
||||||
|
{% for p in most_returned_products %}
|
||||||
|
<li class="py-2 first:pt-0 last:pb-0">
|
||||||
|
<a href="{{ p.admin_url }}" class="flex items-center gap-4">
|
||||||
|
{% if p.image %}
|
||||||
|
<img src="{{ p.image }}" alt="{{ p.name }}"
|
||||||
|
class="w-12 h-12 object-cover rounded"/>
|
||||||
|
{% endif %}
|
||||||
|
<span class="font-medium flex-1 truncate">{{ p.name }}</span>
|
||||||
|
<span class="text-xs px-2 py-0.5 rounded bg-red-500/10 text-red-700 dark:text-red-300">×{{ p.count }}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
{% component "unfold/components/text.html" %}
|
||||||
|
{% trans "No returns in the last 30 days." %}
|
||||||
|
{% endcomponent %}
|
||||||
|
{% endif %}
|
||||||
|
{% endcomponent %}
|
||||||
71
engine/core/templates/admin/dashboard/_product_lists.html
Normal file
71
engine/core/templates/admin/dashboard/_product_lists.html
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
{% load i18n unfold %}
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mt-6">
|
||||||
|
{% component "unfold/components/card.html" %}
|
||||||
|
{% component "unfold/components/title.html" %}
|
||||||
|
{% trans "Most wished product" %}
|
||||||
|
{% endcomponent %}
|
||||||
|
{% if most_wished_products %}
|
||||||
|
<ul class="flex flex-col divide-y divide-gray-200 dark:divide-base-700/50">
|
||||||
|
{% for p in most_wished_products %}
|
||||||
|
<li class="py-2 first:pt-0 last:pb-0">
|
||||||
|
<a href="{{ p.admin_url }}" class="flex items-center gap-4">
|
||||||
|
{% if p.image %}
|
||||||
|
<img src="{{ p.image }}" alt="{{ p.name }}"
|
||||||
|
class="w-12 h-12 object-cover rounded"/>
|
||||||
|
{% endif %}
|
||||||
|
<span class="font-medium flex-1 truncate">{{ p.name }}</span>
|
||||||
|
<span class="text-xs px-2 py-0.5 rounded bg-base-700/[.06] dark:bg-white/[.06] text-gray-700 dark:text-gray-200">{{ p.count }}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% elif most_wished_product %}
|
||||||
|
<a href="{{ most_wished_product.admin_url }}" class="flex items-center gap-4">
|
||||||
|
{% if most_wished_product.image %}
|
||||||
|
<img src="{{ most_wished_product.image }}" alt="{{ most_wished_product.name }}"
|
||||||
|
class="w-16 h-16 object-cover rounded"/>
|
||||||
|
{% endif %}
|
||||||
|
<span class="font-medium">{{ most_wished_product.name }}</span>
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
{% component "unfold/components/text.html" %}
|
||||||
|
{% trans "No data yet." %}
|
||||||
|
{% endcomponent %}
|
||||||
|
{% endif %}
|
||||||
|
{% endcomponent %}
|
||||||
|
|
||||||
|
{% component "unfold/components/card.html" %}
|
||||||
|
{% component "unfold/components/title.html" %}
|
||||||
|
{% trans "Most popular product" %}
|
||||||
|
{% endcomponent %}
|
||||||
|
{% if most_popular_products %}
|
||||||
|
<ul class="flex flex-col divide-y divide-gray-200 dark:divide-base-700/50">
|
||||||
|
{% for p in most_popular_products %}
|
||||||
|
<li class="py-2 first:pt-0 last:pb-0">
|
||||||
|
<a href="{{ p.admin_url }}" class="flex items-center gap-4">
|
||||||
|
{% if p.image %}
|
||||||
|
<img src="{{ p.image }}" alt="{{ p.name }}"
|
||||||
|
class="w-12 h-12 object-cover rounded"/>
|
||||||
|
{% endif %}
|
||||||
|
<span class="font-medium flex-1 truncate">{{ p.name }}</span>
|
||||||
|
<span class="text-xs px-2 py-0.5 rounded bg-base-700/[.06] dark:bg-white/[.06] text-gray-700 dark:text-gray-200">{{ p.count }}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% elif most_popular_product %}
|
||||||
|
<a href="{{ most_popular_product.admin_url }}" class="flex items-center gap-4">
|
||||||
|
{% if most_popular_product.image %}
|
||||||
|
<img src="{{ most_popular_product.image }}" alt="{{ most_popular_product.name }}"
|
||||||
|
class="w-16 h-16 object-cover rounded"/>
|
||||||
|
{% endif %}
|
||||||
|
<span class="font-medium">{{ most_popular_product.name }}</span>
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
{% component "unfold/components/text.html" %}
|
||||||
|
{% trans "No data yet." %}
|
||||||
|
{% endcomponent %}
|
||||||
|
{% endif %}
|
||||||
|
{% endcomponent %}
|
||||||
|
</div>
|
||||||
15
engine/core/templates/admin/dashboard/_quick_links.html
Normal file
15
engine/core/templates/admin/dashboard/_quick_links.html
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
{% load i18n unfold %}
|
||||||
|
|
||||||
|
{% component "unfold/components/card.html" %}
|
||||||
|
{% component "unfold/components/title.html" %}
|
||||||
|
{% trans "Quick Links" %}
|
||||||
|
{% endcomponent %}
|
||||||
|
{% if quick_links %}
|
||||||
|
{% component "unfold/components/navigation.html" with class="flex flex-col gap-1" items=quick_links %}
|
||||||
|
{% endcomponent %}
|
||||||
|
{% else %}
|
||||||
|
{% component "unfold/components/text.html" %}
|
||||||
|
{% trans "No links available." %}
|
||||||
|
{% endcomponent %}
|
||||||
|
{% endif %}
|
||||||
|
{% endcomponent %}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
{% load i18n unfold %}
|
||||||
|
|
||||||
|
{% component "unfold/components/card.html" %}
|
||||||
|
{% component "unfold/components/title.html" %}
|
||||||
|
{% trans "Shipped vs Digital (30d)" %}
|
||||||
|
{% endcomponent %}
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-3">
|
||||||
|
<div class="flex items-center justify-between text-sm">
|
||||||
|
<span class="text-gray-600 dark:text-gray-300">{% trans "Digital" %}</span>
|
||||||
|
<span class="font-medium">
|
||||||
|
{{ shipped_vs_digital.digital_qty }} ({% firstof shipped_vs_digital.digital_pct 0 %}%) ·
|
||||||
|
{% if currency_symbol %}{{ currency_symbol }}{% endif %}{{ shipped_vs_digital.digital_gross }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{% component "unfold/components/progress.html" with value=shipped_vs_digital.digital_pct title='' description='' %}
|
||||||
|
{% endcomponent %}
|
||||||
|
|
||||||
|
<div class="flex items-center justify-between text-sm mt-2">
|
||||||
|
<span class="text-gray-600 dark:text-gray-300">{% trans "Shipped" %}</span>
|
||||||
|
<span class="font-medium">
|
||||||
|
{{ shipped_vs_digital.shipped_qty }} ({% firstof shipped_vs_digital.shipped_pct 0 %}%) ·
|
||||||
|
{% if currency_symbol %}{{ currency_symbol }}{% endif %}{{ shipped_vs_digital.shipped_gross }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{% component "unfold/components/progress.html" with value=shipped_vs_digital.shipped_pct title='' description='' %}
|
||||||
|
{% endcomponent %}
|
||||||
|
</div>
|
||||||
|
{% endcomponent %}
|
||||||
26
engine/core/templates/admin/dashboard/_top_categories.html
Normal file
26
engine/core/templates/admin/dashboard/_top_categories.html
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
{% load i18n unfold %}
|
||||||
|
|
||||||
|
{% component "unfold/components/card.html" %}
|
||||||
|
{% component "unfold/components/title.html" %}
|
||||||
|
{% trans "Top categories by quantity (30d)" %}
|
||||||
|
{% endcomponent %}
|
||||||
|
{% if top_categories %}
|
||||||
|
<ul class="flex flex-col divide-y divide-gray-200 dark:divide-base-700/50">
|
||||||
|
{% for c in top_categories %}
|
||||||
|
<li class="py-2 first:pt-0 last:pb-0">
|
||||||
|
<a href="{{ c.admin_url }}" class="flex items-center gap-4">
|
||||||
|
<span class="font-medium flex-1 truncate">{{ c.name }}</span>
|
||||||
|
<span class="text-xs px-2 py-0.5 rounded bg-base-700/[.06] dark:bg-white/[.06] text-gray-700 dark:text-gray-200">{{ c.qty }}</span>
|
||||||
|
<span class="text-xs text-gray-600 dark:text-gray-300 whitespace-nowrap">
|
||||||
|
{% if currency_symbol %}{{ currency_symbol }}{% endif %}{{ c.gross }}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
{% component "unfold/components/text.html" %}
|
||||||
|
{% trans "No category sales in the last 30 days." %}
|
||||||
|
{% endcomponent %}
|
||||||
|
{% endif %}
|
||||||
|
{% endcomponent %}
|
||||||
|
|
@ -21,383 +21,28 @@
|
||||||
<br/>
|
<br/>
|
||||||
{% endcomponent %}
|
{% endcomponent %}
|
||||||
|
|
||||||
<div class="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-4 mb-6">
|
{% include "admin/dashboard/_kpis.html" %}
|
||||||
{% component "unfold/components/card.html" %}
|
|
||||||
{% component "unfold/components/text.html" %}
|
|
||||||
{% trans "Revenue (gross, 30d)" %}
|
|
||||||
{% endcomponent %}
|
|
||||||
{% component "unfold/components/title.html" %}
|
|
||||||
{% if currency_symbol %}{{ currency_symbol }}{% endif %}{{ revenue_gross_30|default:0 }}
|
|
||||||
{% endcomponent %}
|
|
||||||
{% endcomponent %}
|
|
||||||
|
|
||||||
{% component "unfold/components/card.html" %}
|
|
||||||
{% component "unfold/components/text.html" %}
|
|
||||||
{% trans "Revenue (net, 30d)" %}
|
|
||||||
{% endcomponent %}
|
|
||||||
{% component "unfold/components/title.html" %}
|
|
||||||
{% if currency_symbol %}{{ currency_symbol }}{% endif %}{{ revenue_net_30|default:0 }}
|
|
||||||
{% endcomponent %}
|
|
||||||
{% endcomponent %}
|
|
||||||
|
|
||||||
{% component "unfold/components/card.html" %}
|
|
||||||
{% component "unfold/components/text.html" %}
|
|
||||||
{% trans "Returns (30d)" %}
|
|
||||||
{% endcomponent %}
|
|
||||||
{% component "unfold/components/title.html" %}
|
|
||||||
{% if currency_symbol %}{{ currency_symbol }}{% endif %}{{ returns_30|default:0 }}
|
|
||||||
{% endcomponent %}
|
|
||||||
{% endcomponent %}
|
|
||||||
|
|
||||||
{% component "unfold/components/card.html" %}
|
|
||||||
{% component "unfold/components/text.html" %}
|
|
||||||
{% trans "Processed orders (30d)" %}
|
|
||||||
{% endcomponent %}
|
|
||||||
{% component "unfold/components/title.html" %}
|
|
||||||
{{ processed_orders_30|default:0 }}
|
|
||||||
{% endcomponent %}
|
|
||||||
{% endcomponent %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="grid grid-cols-1 xl:grid-cols-3 gap-6 items-start">
|
<div class="grid grid-cols-1 xl:grid-cols-3 gap-6 items-start">
|
||||||
{% with gross=revenue_gross_30|default:0 returns=returns_30|default:0 %}
|
{% include "admin/dashboard/_income_overview.html" %}
|
||||||
{% with total=gross|add:returns %}
|
{% include "admin/dashboard/_quick_links.html" %}
|
||||||
{% component "unfold/components/card.html" with class="xl:col-span-2" %}
|
|
||||||
{% component "unfold/components/title.html" %}
|
|
||||||
{% trans "Income overview" %}
|
|
||||||
{% endcomponent %}
|
|
||||||
{% if total and total > 0 %}
|
|
||||||
{% with net=revenue_net_30|default:0 %}
|
|
||||||
{% with tax_amt=gross|sub:net %}
|
|
||||||
{% with returns_capped=returns %}
|
|
||||||
{% if returns > gross %}
|
|
||||||
{% with returns_capped=gross %}{% endwith %}
|
|
||||||
{% endif %}
|
|
||||||
{% with tax_amt_pos=tax_amt %}
|
|
||||||
{% if tax_amt_pos < 0 %}
|
|
||||||
{% with tax_amt_pos=0 %}{% endwith %}
|
|
||||||
{% endif %}
|
|
||||||
{% with net_for_pie=gross|sub:tax_amt_pos|sub:returns_capped %}
|
|
||||||
{% if net_for_pie < 0 %}
|
|
||||||
{% with net_for_pie=0 %}{% endwith %}
|
|
||||||
{% endif %}
|
|
||||||
{% widthratio net_for_pie gross 360 as net_deg %}
|
|
||||||
{% widthratio tax_amt_pos gross 360 as tax_deg %}
|
|
||||||
{% widthratio returns_capped gross 360 as ret_deg %}
|
|
||||||
{% with net_end=net_deg %}
|
|
||||||
{% with tax_end=net_end|add:tax_deg %}
|
|
||||||
{% with ret_end=tax_end|add:ret_deg %}
|
|
||||||
<div class="flex flex-col sm:flex-row items-center gap-6">
|
|
||||||
<div class="relative w-48 h-48">
|
|
||||||
<canvas id="incomePieChart" width="192"
|
|
||||||
height="192"></canvas>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="flex items-center gap-2 mb-2">
|
|
||||||
<span class="inline-block w-3 h-3 rounded-sm"
|
|
||||||
style="background:rgb(34,197,94)"></span>
|
|
||||||
<span class="text-sm text-gray-600 dark:text-gray-300">{% trans "Net" %}:</span>
|
|
||||||
<span class="font-semibold">{% if currency_symbol %}
|
|
||||||
{{ currency_symbol }}{% endif %}{{ net }}</span>
|
|
||||||
</div>
|
|
||||||
{% if tax_amt_pos > 0 %}
|
|
||||||
<div class="flex items-center gap-2 mb-2">
|
|
||||||
<span class="inline-block w-3 h-3 rounded-sm"
|
|
||||||
style="background:rgb(249,115,22)"></span>
|
|
||||||
<span class="text-sm text-gray-600 dark:text-gray-300">{% trans "Taxes" %}:</span>
|
|
||||||
<span class="font-semibold">{% if currency_symbol %}
|
|
||||||
{{ currency_symbol }}{% endif %}{{ tax_amt_pos|floatformat:2 }}</span>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
<div class="flex items-center gap-2 mb-2">
|
|
||||||
<span class="inline-block w-3 h-3 rounded-sm"
|
|
||||||
style="background:rgb(239,68,68)"></span>
|
|
||||||
<span class="text-sm text-gray-600 dark:text-gray-300">{% trans "Returns" %}:</span>
|
|
||||||
<span class="font-semibold">{% if currency_symbol %}
|
|
||||||
{{ currency_symbol }}{% endif %}{{ returns }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<span class="inline-block w-3 h-3 rounded-sm"
|
|
||||||
style="background:linear-gradient(90deg, rgba(0,0,0,0.15), rgba(0,0,0,0.15))"></span>
|
|
||||||
<span class="text-sm text-gray-600 dark:text-gray-300">{% trans "Gross (pie total)" %}:</span>
|
|
||||||
<span class="font-semibold">{% if currency_symbol %}
|
|
||||||
{{ currency_symbol }}{% endif %}{{ gross }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
||||||
<script>
|
|
||||||
(function () {
|
|
||||||
try {
|
|
||||||
const ctx = document.getElementById('incomePieChart').getContext('2d');
|
|
||||||
const dataValues = [
|
|
||||||
{{ net_for_pie|floatformat:2 }},
|
|
||||||
{{ tax_amt_pos|floatformat:2 }},
|
|
||||||
{{ returns_capped|floatformat:2 }}
|
|
||||||
];
|
|
||||||
const labels = [
|
|
||||||
'{{ _("Net") }}',
|
|
||||||
'{{ _("Taxes") }}',
|
|
||||||
'{{ _("Returns") }}'
|
|
||||||
];
|
|
||||||
|
|
||||||
const colors = [
|
|
||||||
'rgb(34,197,94)',
|
|
||||||
'rgb(249,115,22)',
|
|
||||||
'rgb(239,68,68)'
|
|
||||||
];
|
|
||||||
|
|
||||||
const hasData = dataValues.some(function (v) {
|
|
||||||
return Number(v) > 0;
|
|
||||||
});
|
|
||||||
if (!hasData) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const currency = "{% if currency_symbol %}{{ currency_symbol }}{% endif %}";
|
|
||||||
new Chart(ctx, {
|
|
||||||
type: 'doughnut',
|
|
||||||
data: {
|
|
||||||
labels: labels,
|
|
||||||
datasets: [{
|
|
||||||
data: dataValues,
|
|
||||||
backgroundColor: colors,
|
|
||||||
borderWidth: 0,
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
maintainAspectRatio: false,
|
|
||||||
plugins: {
|
|
||||||
legend: {position: 'bottom'},
|
|
||||||
tooltip: {
|
|
||||||
callbacks: {
|
|
||||||
label: function (context) {
|
|
||||||
const label = context.label || '';
|
|
||||||
const val = context.parsed || 0;
|
|
||||||
return `${label}: ${currency}${val}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
cutout: '55%'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
console && console.warn && console.warn('Pie chart init failed', e);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
{% endwith %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endwith %}
|
|
||||||
{% else %}
|
|
||||||
{% component "unfold/components/text.html" %}
|
|
||||||
{% trans "Not enough data for chart yet." %}
|
|
||||||
{% endcomponent %}
|
|
||||||
{% endif %}
|
|
||||||
{% endcomponent %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endwith %}
|
|
||||||
|
|
||||||
{% component "unfold/components/card.html" %}
|
|
||||||
{% component "unfold/components/title.html" %}
|
|
||||||
{% trans "Quick Links" %}
|
|
||||||
{% endcomponent %}
|
|
||||||
{% if quick_links %}
|
|
||||||
{% component "unfold/components/navigation.html" with class="flex flex-col gap-1" items=quick_links %}
|
|
||||||
{% endcomponent %}
|
|
||||||
{% else %}
|
|
||||||
{% component "unfold/components/text.html" %}
|
|
||||||
{% trans "No links available." %}
|
|
||||||
{% endcomponent %}
|
|
||||||
{% endif %}
|
|
||||||
{% endcomponent %}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% component "unfold/components/card.html" %}
|
{% include "admin/dashboard/_daily_sales.html" %}
|
||||||
{% component "unfold/components/title.html" %}
|
|
||||||
{% trans "Daily sales (30d)" %}
|
|
||||||
{% endcomponent %}
|
|
||||||
{% if daily_labels and daily_labels|length > 0 %}
|
|
||||||
<div class="w-full">
|
|
||||||
<canvas id="dailySalesChart" height="120"></canvas>
|
|
||||||
</div>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
||||||
{{ daily_labels|json_script:"daily-labels" }}
|
|
||||||
{{ daily_orders|json_script:"daily-orders" }}
|
|
||||||
{{ daily_gross|json_script:"daily-gross" }}
|
|
||||||
<script>
|
|
||||||
(function () {
|
|
||||||
try {
|
|
||||||
const labels = JSON.parse(document.getElementById('daily-labels').textContent);
|
|
||||||
const orders = JSON.parse(document.getElementById('daily-orders').textContent);
|
|
||||||
const gross = JSON.parse(document.getElementById('daily-gross').textContent);
|
|
||||||
|
|
||||||
const ctx = document.getElementById('dailySalesChart').getContext('2d');
|
|
||||||
const green = 'rgb(34,197,94)';
|
|
||||||
const blue = 'rgb(59,130,246)';
|
|
||||||
|
|
||||||
const currency = "{% if currency_symbol %}{{ currency_symbol }}{% endif %}";
|
|
||||||
|
|
||||||
new Chart(ctx, {
|
|
||||||
type: 'line',
|
|
||||||
data: {
|
|
||||||
labels: labels,
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
label: '{{ _("Orders (FINISHED)") }}',
|
|
||||||
data: orders,
|
|
||||||
borderColor: green,
|
|
||||||
backgroundColor: green,
|
|
||||||
borderWidth: 2,
|
|
||||||
tension: 0.25,
|
|
||||||
pointRadius: 2,
|
|
||||||
yAxisID: 'yOrders',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '{{ _("Gross revenue") }}',
|
|
||||||
data: gross,
|
|
||||||
borderColor: blue,
|
|
||||||
backgroundColor: blue,
|
|
||||||
borderWidth: 2,
|
|
||||||
tension: 0.25,
|
|
||||||
pointRadius: 2,
|
|
||||||
yAxisID: 'yRevenue',
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
maintainAspectRatio: false,
|
|
||||||
interaction: {mode: 'index', intersect: false},
|
|
||||||
plugins: {
|
|
||||||
legend: {display: true},
|
|
||||||
tooltip: {
|
|
||||||
callbacks: {
|
|
||||||
label: function (context) {
|
|
||||||
const label = context.dataset.label || '';
|
|
||||||
const val = context.parsed.y;
|
|
||||||
if (context.dataset.yAxisID === 'yRevenue') {
|
|
||||||
return `${label}: ${currency}${val}`;
|
|
||||||
}
|
|
||||||
return `${label}: ${val}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
scales: {
|
|
||||||
x: {
|
|
||||||
grid: {display: false}
|
|
||||||
},
|
|
||||||
yOrders: {
|
|
||||||
type: 'linear',
|
|
||||||
position: 'left',
|
|
||||||
title: {display: true, text: '{{ _("Orders") }}'},
|
|
||||||
grid: {color: 'rgba(0,0,0,0.06)'},
|
|
||||||
ticks: {precision: 0}
|
|
||||||
},
|
|
||||||
yRevenue: {
|
|
||||||
type: 'linear',
|
|
||||||
position: 'right',
|
|
||||||
title: {display: true, text: '{{ _("Gross") }}'},
|
|
||||||
grid: {drawOnChartArea: false},
|
|
||||||
ticks: {
|
|
||||||
callback: function (value) {
|
|
||||||
return `${currency}${value}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
console && console.warn && console.warn('Chart init failed', e);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
{% else %}
|
|
||||||
{% component "unfold/components/text.html" %}
|
|
||||||
{% trans "Not enough data for chart yet." %}
|
|
||||||
{% endcomponent %}
|
|
||||||
{% endif %}
|
|
||||||
{% endcomponent %}
|
|
||||||
|
|
||||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mt-6">
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mt-6">
|
||||||
{% component "unfold/components/card.html" %}
|
{% include "admin/dashboard/_customers_mix.html" %}
|
||||||
{% component "unfold/components/title.html" %}
|
{% if shipped_vs_digital.digital_qty|default:0 > 0 and shipped_vs_digital.shipped_qty|default:0 > 0 %}
|
||||||
{% trans "Most wished product" %}
|
{% include "admin/dashboard/_shipped_vs_digital.html" %}
|
||||||
{% endcomponent %}
|
{% endif %}
|
||||||
{% if most_wished_products %}
|
|
||||||
<ul class="flex flex-col divide-y divide-gray-200 dark:divide-base-700/50">
|
|
||||||
{% for p in most_wished_products %}
|
|
||||||
<li class="py-2 first:pt-0 last:pb-0">
|
|
||||||
<a href="{{ p.admin_url }}" class="flex items-center gap-4">
|
|
||||||
{% if p.image %}
|
|
||||||
<img src="{{ p.image }}" alt="{{ p.name }}"
|
|
||||||
class="w-12 h-12 object-cover rounded"/>
|
|
||||||
{% endif %}
|
|
||||||
<span class="font-medium flex-1 truncate">{{ p.name }}</span>
|
|
||||||
<span class="text-xs px-2 py-0.5 rounded bg-base-700/[.06] dark:bg-white/[.06] text-gray-700 dark:text-gray-200">{{ p.count }}</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% elif most_wished_product %}
|
|
||||||
<a href="{{ most_wished_product.admin_url }}" class="flex items-center gap-4">
|
|
||||||
{% if most_wished_product.image %}
|
|
||||||
<img src="{{ most_wished_product.image }}" alt="{{ most_wished_product.name }}"
|
|
||||||
class="w-16 h-16 object-cover rounded"/>
|
|
||||||
{% endif %}
|
|
||||||
<span class="font-medium">{{ most_wished_product.name }}</span>
|
|
||||||
</a>
|
|
||||||
{% else %}
|
|
||||||
{% component "unfold/components/text.html" %}
|
|
||||||
{% trans "No data yet." %}
|
|
||||||
{% endcomponent %}
|
|
||||||
{% endif %}
|
|
||||||
{% endcomponent %}
|
|
||||||
|
|
||||||
{% component "unfold/components/card.html" %}
|
|
||||||
{% component "unfold/components/title.html" %}
|
|
||||||
{% trans "Most popular product" %}
|
|
||||||
{% endcomponent %}
|
|
||||||
{% if most_popular_products %}
|
|
||||||
<ul class="flex flex-col divide-y divide-gray-200 dark:divide-base-700/50">
|
|
||||||
{% for p in most_popular_products %}
|
|
||||||
<li class="py-2 first:pt-0 last:pb-0">
|
|
||||||
<a href="{{ p.admin_url }}" class="flex items-center gap-4">
|
|
||||||
{% if p.image %}
|
|
||||||
<img src="{{ p.image }}" alt="{{ p.name }}"
|
|
||||||
class="w-12 h-12 object-cover rounded"/>
|
|
||||||
{% endif %}
|
|
||||||
<span class="font-medium flex-1 truncate">{{ p.name }}</span>
|
|
||||||
<span class="text-xs px-2 py-0.5 rounded bg-base-700/[.06] dark:bg-white/[.06] text-gray-700 dark:text-gray-200">{{ p.count }}</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% elif most_popular_product %}
|
|
||||||
<a href="{{ most_popular_product.admin_url }}" class="flex items-center gap-4">
|
|
||||||
{% if most_popular_product.image %}
|
|
||||||
<img src="{{ most_popular_product.image }}" alt="{{ most_popular_product.name }}"
|
|
||||||
class="w-16 h-16 object-cover rounded"/>
|
|
||||||
{% endif %}
|
|
||||||
<span class="font-medium">{{ most_popular_product.name }}</span>
|
|
||||||
</a>
|
|
||||||
{% else %}
|
|
||||||
{% component "unfold/components/text.html" %}
|
|
||||||
{% trans "No data yet." %}
|
|
||||||
{% endcomponent %}
|
|
||||||
{% endif %}
|
|
||||||
{% endcomponent %}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mt-6">
|
||||||
|
{% include "admin/dashboard/_most_returned.html" %}
|
||||||
|
{% include "admin/dashboard/_top_categories.html" %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% include "admin/dashboard/_product_lists.html" %}
|
||||||
|
|
||||||
{% component "unfold/components/separator.html" %}
|
{% component "unfold/components/separator.html" %}
|
||||||
{% endcomponent %}
|
{% endcomponent %}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from datetime import date, timedelta
|
from datetime import date, timedelta
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from constance import config
|
from constance import config
|
||||||
from django.db.models import Count, F, QuerySet, Sum
|
from django.db.models import Count, F, QuerySet, Sum
|
||||||
from django.db.models.functions import Coalesce, TruncDate
|
from django.db.models.functions import Coalesce, TruncDate
|
||||||
|
from django.urls import reverse
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
|
|
||||||
from engine.core.models import Order, OrderProduct
|
from engine.core.models import Category, Order, OrderProduct, Product
|
||||||
|
|
||||||
|
|
||||||
def get_period_order_products(
|
def get_period_order_products(
|
||||||
|
|
@ -110,3 +112,156 @@ def get_daily_gross_revenue(period: timedelta = timedelta(days=30)) -> dict[date
|
||||||
if d:
|
if d:
|
||||||
result[d] = total_f
|
result[d] = total_f
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def get_top_returned_products(period: timedelta = timedelta(days=30), limit: int = 10) -> list[dict[str, Any]]:
|
||||||
|
current = now()
|
||||||
|
period_start = current - period
|
||||||
|
qs = (
|
||||||
|
OrderProduct.objects.filter(
|
||||||
|
status="RETURNED",
|
||||||
|
order__status="FINISHED",
|
||||||
|
order__buy_time__lte=current,
|
||||||
|
order__buy_time__gte=period_start,
|
||||||
|
product__isnull=False,
|
||||||
|
)
|
||||||
|
.values("product")
|
||||||
|
.annotate(
|
||||||
|
returned_qty=Coalesce(Sum("quantity"), 0),
|
||||||
|
returned_amount=Coalesce(Sum(F("buy_price") * F("quantity")), 0.0),
|
||||||
|
)
|
||||||
|
.order_by("-returned_qty")[:limit]
|
||||||
|
)
|
||||||
|
|
||||||
|
result: list[dict[str, Any]] = []
|
||||||
|
prod_ids = [row["product"] for row in qs if row.get("product")]
|
||||||
|
products = Product.objects.filter(pk__in=prod_ids)
|
||||||
|
product_by_id = {p.pk: p for p in products}
|
||||||
|
for row in qs:
|
||||||
|
pid = row.get("product")
|
||||||
|
if not pid or pid not in product_by_id:
|
||||||
|
continue
|
||||||
|
p = product_by_id[pid]
|
||||||
|
img = ""
|
||||||
|
with suppress(Exception):
|
||||||
|
img = p.images.first().image_url if p.images.exists() else "" # type: ignore [union-attr]
|
||||||
|
result.append(
|
||||||
|
{
|
||||||
|
"name": p.name,
|
||||||
|
"image": img,
|
||||||
|
"admin_url": reverse("admin:core_product_change", args=[p.pk]),
|
||||||
|
"count": int(row.get("returned_qty", 0) or 0),
|
||||||
|
"amount": round(float(row.get("returned_amount", 0.0) or 0.0), 2),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def get_customer_mix(period: timedelta = timedelta(days=30)) -> dict[str, int]:
|
||||||
|
current = now()
|
||||||
|
period_start = current - period
|
||||||
|
period_users = (
|
||||||
|
Order.objects.filter(status="FINISHED", buy_time__lte=current, buy_time__gte=period_start, user__isnull=False)
|
||||||
|
.values_list("user_id", flat=True)
|
||||||
|
.distinct()
|
||||||
|
)
|
||||||
|
if not period_users:
|
||||||
|
return {"new": 0, "returning": 0}
|
||||||
|
|
||||||
|
lifetime_counts = (
|
||||||
|
Order.objects.filter(status="FINISHED", user_id__in=period_users).values("user_id").annotate(c=Count("id"))
|
||||||
|
)
|
||||||
|
new_cnt = 0
|
||||||
|
ret_cnt = 0
|
||||||
|
for row in lifetime_counts:
|
||||||
|
c = int(row.get("c", 0) or 0)
|
||||||
|
if c <= 1:
|
||||||
|
new_cnt += 1
|
||||||
|
else:
|
||||||
|
ret_cnt += 1
|
||||||
|
return {"new": new_cnt, "returning": ret_cnt}
|
||||||
|
|
||||||
|
|
||||||
|
def get_top_categories_by_qty(period: timedelta = timedelta(days=30), limit: int = 10) -> list[dict[str, Any]]:
|
||||||
|
current = now()
|
||||||
|
period_start = current - period
|
||||||
|
qs = (
|
||||||
|
OrderProduct.objects.filter(
|
||||||
|
status="FINISHED",
|
||||||
|
order__status="FINISHED",
|
||||||
|
order__buy_time__lte=current,
|
||||||
|
order__buy_time__gte=period_start,
|
||||||
|
product__isnull=False,
|
||||||
|
product__category__isnull=False,
|
||||||
|
)
|
||||||
|
.values("product__category")
|
||||||
|
.annotate(
|
||||||
|
qty=Coalesce(Sum("quantity"), 0),
|
||||||
|
gross=Coalesce(Sum(F("buy_price") * F("quantity")), 0.0),
|
||||||
|
)
|
||||||
|
.order_by("-qty", "-gross")[:limit]
|
||||||
|
)
|
||||||
|
|
||||||
|
cat_ids = [row["product__category"] for row in qs if row.get("product__category")]
|
||||||
|
cats = Category.objects.filter(pk__in=cat_ids)
|
||||||
|
cat_by_id = {c.pk: c for c in cats}
|
||||||
|
result: list[dict[str, Any]] = []
|
||||||
|
for row in qs:
|
||||||
|
cid = row.get("product__category")
|
||||||
|
if not cid or cid not in cat_by_id:
|
||||||
|
continue
|
||||||
|
c = cat_by_id[cid]
|
||||||
|
result.append(
|
||||||
|
{
|
||||||
|
"name": c.name,
|
||||||
|
"admin_url": reverse("admin:core_category_change", args=[c.pk]),
|
||||||
|
"qty": int(row.get("qty", 0) or 0),
|
||||||
|
"gross": round(float(row.get("gross", 0.0) or 0.0), 2),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def get_shipped_vs_digital_mix(period: timedelta = timedelta(days=30)) -> dict[str, float | int]:
|
||||||
|
current = now()
|
||||||
|
period_start = current - period
|
||||||
|
qs = (
|
||||||
|
OrderProduct.objects.filter(
|
||||||
|
status="FINISHED",
|
||||||
|
order__status="FINISHED",
|
||||||
|
order__buy_time__lte=current,
|
||||||
|
order__buy_time__gte=period_start,
|
||||||
|
product__isnull=False,
|
||||||
|
)
|
||||||
|
.values("product__is_digital")
|
||||||
|
.annotate(
|
||||||
|
qty=Coalesce(Sum("quantity"), 0),
|
||||||
|
gross=Coalesce(Sum(F("buy_price") * F("quantity")), 0.0),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
digital_qty = 0
|
||||||
|
shipped_qty = 0
|
||||||
|
digital_gross = 0.0
|
||||||
|
shipped_gross = 0.0
|
||||||
|
for row in qs:
|
||||||
|
is_digital = bool(row.get("product__is_digital"))
|
||||||
|
q = int(row.get("qty", 0) or 0)
|
||||||
|
g = row.get("gross", 0.0) or 0.0
|
||||||
|
try:
|
||||||
|
g = float(g)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
g = 0.0
|
||||||
|
if is_digital:
|
||||||
|
digital_qty += q
|
||||||
|
digital_gross += g
|
||||||
|
else:
|
||||||
|
shipped_qty += q
|
||||||
|
shipped_gross += g
|
||||||
|
|
||||||
|
return {
|
||||||
|
"digital_qty": int(digital_qty),
|
||||||
|
"shipped_qty": int(shipped_qty),
|
||||||
|
"digital_gross": round(float(digital_gross), 2),
|
||||||
|
"shipped_gross": round(float(shipped_gross), 2),
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import logging
|
import logging
|
||||||
from datetime import timedelta
|
|
||||||
import mimetypes
|
import mimetypes
|
||||||
import os
|
import os
|
||||||
import traceback
|
import traceback
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
@ -18,8 +18,8 @@ from django.template import Context
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.utils.http import urlsafe_base64_decode
|
from django.utils.http import urlsafe_base64_decode
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
from django.utils.timezone import now as tz_now
|
from django.utils.timezone import now as tz_now
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.views.decorators.cache import cache_page
|
from django.views.decorators.cache import cache_page
|
||||||
from django.views.decorators.vary import vary_on_headers
|
from django.views.decorators.vary import vary_on_headers
|
||||||
from django_ratelimit.decorators import ratelimit
|
from django_ratelimit.decorators import ratelimit
|
||||||
|
|
@ -60,11 +60,15 @@ from engine.core.serializers import (
|
||||||
from engine.core.utils import get_project_parameters, is_url_safe
|
from engine.core.utils import get_project_parameters, is_url_safe
|
||||||
from engine.core.utils.caching import web_cache
|
from engine.core.utils.caching import web_cache
|
||||||
from engine.core.utils.commerce import (
|
from engine.core.utils.commerce import (
|
||||||
get_returns,
|
get_customer_mix,
|
||||||
get_revenue,
|
|
||||||
get_total_processed_orders,
|
|
||||||
get_daily_finished_orders_count,
|
get_daily_finished_orders_count,
|
||||||
get_daily_gross_revenue,
|
get_daily_gross_revenue,
|
||||||
|
get_returns,
|
||||||
|
get_revenue,
|
||||||
|
get_shipped_vs_digital_mix,
|
||||||
|
get_top_categories_by_qty,
|
||||||
|
get_top_returned_products,
|
||||||
|
get_total_processed_orders,
|
||||||
)
|
)
|
||||||
from engine.core.utils.emailing import contact_us_email
|
from engine.core.utils.emailing import contact_us_email
|
||||||
from engine.core.utils.languages import get_flag_by_language
|
from engine.core.utils.languages import get_flag_by_language
|
||||||
|
|
@ -452,9 +456,7 @@ def dashboard_callback(request: HttpRequest, context: Context) -> Context:
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Single most wished product (backward compatibility)
|
|
||||||
most_wished: dict[str, str | int | float | None] | None = None
|
most_wished: dict[str, str | int | float | None] | None = None
|
||||||
# Top 10 most wished products
|
|
||||||
most_wished_list: list[dict[str, str | int | float | None]] = []
|
most_wished_list: list[dict[str, str | int | float | None]] = []
|
||||||
with suppress(Exception):
|
with suppress(Exception):
|
||||||
wished_qs = (
|
wished_qs = (
|
||||||
|
|
@ -475,12 +477,10 @@ def dashboard_callback(request: HttpRequest, context: Context) -> Context:
|
||||||
"admin_url": reverse("admin:core_product_change", args=[product.pk]),
|
"admin_url": reverse("admin:core_product_change", args=[product.pk]),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Build top 10 list
|
|
||||||
wished_top10 = list(wished_qs[:10])
|
wished_top10 = list(wished_qs[:10])
|
||||||
if wished_top10:
|
if wished_top10:
|
||||||
counts_map = {row["products"]: row["cnt"] for row in wished_top10 if row.get("products")}
|
counts_map = {row["products"]: row["cnt"] for row in wished_top10 if row.get("products")}
|
||||||
products = Product.objects.filter(pk__in=counts_map.keys())
|
products = Product.objects.filter(pk__in=counts_map.keys())
|
||||||
# Preserve order as in wished_top10
|
|
||||||
product_by_id = {p.pk: p for p in products}
|
product_by_id = {p.pk: p for p in products}
|
||||||
for row in wished_top10:
|
for row in wished_top10:
|
||||||
pid = row.get("products")
|
pid = row.get("products")
|
||||||
|
|
@ -497,9 +497,7 @@ def dashboard_callback(request: HttpRequest, context: Context) -> Context:
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Daily stats for the last 30 days
|
|
||||||
try:
|
try:
|
||||||
# Build continuous date axis
|
|
||||||
today = tz_now().date()
|
today = tz_now().date()
|
||||||
days = 30
|
days = 30
|
||||||
date_axis = [today - timedelta(days=i) for i in range(days - 1, -1, -1)]
|
date_axis = [today - timedelta(days=i) for i in range(days - 1, -1, -1)]
|
||||||
|
|
@ -507,7 +505,6 @@ def dashboard_callback(request: HttpRequest, context: Context) -> Context:
|
||||||
orders_map = get_daily_finished_orders_count(timedelta(days=days))
|
orders_map = get_daily_finished_orders_count(timedelta(days=days))
|
||||||
gross_map = get_daily_gross_revenue(timedelta(days=days))
|
gross_map = get_daily_gross_revenue(timedelta(days=days))
|
||||||
|
|
||||||
# Labels in day-month format, e.g., 05 Nov
|
|
||||||
labels = [d.strftime("%d %b") for d in date_axis]
|
labels = [d.strftime("%d %b") for d in date_axis]
|
||||||
orders_series = [int(orders_map.get(d, 0) or 0) for d in date_axis]
|
orders_series = [int(orders_map.get(d, 0) or 0) for d in date_axis]
|
||||||
gross_series = [float(gross_map.get(d, 0.0) or 0.0) for d in date_axis]
|
gross_series = [float(gross_map.get(d, 0.0) or 0.0) for d in date_axis]
|
||||||
|
|
@ -515,15 +512,20 @@ def dashboard_callback(request: HttpRequest, context: Context) -> Context:
|
||||||
context["daily_labels"] = labels
|
context["daily_labels"] = labels
|
||||||
context["daily_orders"] = orders_series
|
context["daily_orders"] = orders_series
|
||||||
context["daily_gross"] = gross_series
|
context["daily_gross"] = gross_series
|
||||||
except Exception as e: # pragma: no cover - fail safe
|
except Exception as e:
|
||||||
logger.warning("Failed to build daily stats: %s", e)
|
logger.warning("Failed to build daily stats: %s", e)
|
||||||
context["daily_labels"] = []
|
context["daily_labels"] = []
|
||||||
context["daily_orders"] = []
|
context["daily_orders"] = []
|
||||||
context["daily_gross"] = []
|
context["daily_gross"] = []
|
||||||
|
with suppress(Exception):
|
||||||
|
today = tz_now().date()
|
||||||
|
days = 30
|
||||||
|
date_axis = [today - timedelta(days=i) for i in range(days - 1, -1, -1)]
|
||||||
|
context["daily_labels"] = [d.strftime("%d %b") for d in date_axis]
|
||||||
|
context["daily_orders"] = [0 for _ in date_axis]
|
||||||
|
context["daily_gross"] = [0.0 for _ in date_axis]
|
||||||
|
|
||||||
# Single most popular product (backward compatibility)
|
|
||||||
most_popular: dict[str, str | int | float | None] | None = None
|
most_popular: dict[str, str | int | float | None] | None = None
|
||||||
# Top 10 most popular products by quantity
|
|
||||||
most_popular_list: list[dict[str, str | int | float | None]] = []
|
most_popular_list: list[dict[str, str | int | float | None]] = []
|
||||||
with suppress(Exception):
|
with suppress(Exception):
|
||||||
popular_qs = (
|
popular_qs = (
|
||||||
|
|
@ -563,6 +565,50 @@ def dashboard_callback(request: HttpRequest, context: Context) -> Context:
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
customers_mix: dict[str, int | float] = {"new": 0, "returning": 0, "new_pct": 0.0, "returning_pct": 0.0}
|
||||||
|
with suppress(Exception):
|
||||||
|
mix = get_customer_mix()
|
||||||
|
n = int(mix.get("new", 0))
|
||||||
|
r = int(mix.get("returning", 0))
|
||||||
|
t = max(n + r, 0)
|
||||||
|
new_pct = round((n / t * 100.0), 1) if t > 0 else 0.0
|
||||||
|
ret_pct = round((r / t * 100.0), 1) if t > 0 else 0.0
|
||||||
|
customers_mix = {"new": n, "returning": r, "new_pct": new_pct, "returning_pct": ret_pct, "total": t}
|
||||||
|
|
||||||
|
shipped_vs_digital: dict[str, int | float] = {
|
||||||
|
"digital_qty": 0,
|
||||||
|
"shipped_qty": 0,
|
||||||
|
"digital_gross": 0.0,
|
||||||
|
"shipped_gross": 0.0,
|
||||||
|
"digital_pct": 0.0,
|
||||||
|
"shipped_pct": 0.0,
|
||||||
|
}
|
||||||
|
with suppress(Exception):
|
||||||
|
svd = get_shipped_vs_digital_mix()
|
||||||
|
dq = int(svd.get("digital_qty", 0))
|
||||||
|
sq = int(svd.get("shipped_qty", 0))
|
||||||
|
total_q = dq + sq
|
||||||
|
digital_pct = round((dq / total_q * 100.0), 1) if total_q > 0 else 0.0
|
||||||
|
shipped_pct = round((sq / total_q * 100.0), 1) if total_q > 0 else 0.0
|
||||||
|
shipped_vs_digital.update(
|
||||||
|
{
|
||||||
|
"digital_qty": dq,
|
||||||
|
"shipped_qty": sq,
|
||||||
|
"digital_gross": float(svd.get("digital_gross", 0.0) or 0.0),
|
||||||
|
"shipped_gross": float(svd.get("shipped_gross", 0.0) or 0.0),
|
||||||
|
"digital_pct": digital_pct,
|
||||||
|
"shipped_pct": shipped_pct,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
most_returned_products: list[dict[str, str | int | float]] = []
|
||||||
|
with suppress(Exception):
|
||||||
|
most_returned_products = get_top_returned_products()
|
||||||
|
|
||||||
|
top_categories: list[dict[str, str | int | float]] = []
|
||||||
|
with suppress(Exception):
|
||||||
|
top_categories = get_top_categories_by_qty()
|
||||||
|
|
||||||
context.update(
|
context.update(
|
||||||
{
|
{
|
||||||
"custom_variable": "value",
|
"custom_variable": "value",
|
||||||
|
|
@ -577,6 +623,10 @@ def dashboard_callback(request: HttpRequest, context: Context) -> Context:
|
||||||
"most_wished_products": most_wished_list,
|
"most_wished_products": most_wished_list,
|
||||||
"most_popular_products": most_popular_list,
|
"most_popular_products": most_popular_list,
|
||||||
"currency_symbol": currency_symbol,
|
"currency_symbol": currency_symbol,
|
||||||
|
"customers_mix": customers_mix,
|
||||||
|
"shipped_vs_digital": shipped_vs_digital,
|
||||||
|
"most_returned_products": most_returned_products,
|
||||||
|
"top_categories": top_categories,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
"""
|
|
||||||
Deprecated: Jazzmin settings (removed in favor of django-unfold).
|
|
||||||
|
|
||||||
This file is intentionally left as a stub to avoid accidental imports.
|
|
||||||
If imported, raise an explicit error guiding developers to Unfold.
|
|
||||||
"""
|
|
||||||
|
|
||||||
raise ImportError(
|
|
||||||
"Jazzmin configuration has been removed. Use django-unfold instead. "
|
|
||||||
"See evibes/settings/unfold.py and INSTALLED_APPS in evibes/settings/base.py."
|
|
||||||
)
|
|
||||||
|
|
@ -46,6 +46,7 @@ dependencies = [
|
||||||
"djangorestframework-xml==2.0.0",
|
"djangorestframework-xml==2.0.0",
|
||||||
"djangorestframework-yaml==2.0.0",
|
"djangorestframework-yaml==2.0.0",
|
||||||
"djangoql>=0.18.1",
|
"djangoql>=0.18.1",
|
||||||
|
"docutils>=0.21.2",
|
||||||
"drf-spectacular[sidecar]==0.29.0",
|
"drf-spectacular[sidecar]==0.29.0",
|
||||||
"drf-spectacular-websocket>=1.3.1",
|
"drf-spectacular-websocket>=1.3.1",
|
||||||
"elasticsearch-dsl==8.18.0",
|
"elasticsearch-dsl==8.18.0",
|
||||||
|
|
|
||||||
176
uv.lock
176
uv.lock
|
|
@ -224,11 +224,11 @@ wheels = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "asttokens"
|
name = "asttokens"
|
||||||
version = "3.0.0"
|
version = "3.0.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/4a/e7/82da0a03e7ba5141f05cce0d302e6eed121ae055e0456ca228bf693984bc/asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7", size = 61978, upload-time = "2024-11-30T04:30:14.439Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308, upload-time = "2025-11-15T16:43:48.578Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2", size = 26918, upload-time = "2024-11-30T04:30:10.946Z" },
|
{ url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047, upload-time = "2025-11-15T16:43:16.109Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -335,11 +335,11 @@ wheels = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "billiard"
|
name = "billiard"
|
||||||
version = "4.2.2"
|
version = "4.2.3"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/b9/6a/1405343016bce8354b29d90aad6b0bf6485b5e60404516e4b9a3a9646cf0/billiard-4.2.2.tar.gz", hash = "sha256:e815017a062b714958463e07ba15981d802dc53d41c5b69d28c5a7c238f8ecf3", size = 155592, upload-time = "2025-09-20T14:44:40.456Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/6a/50/cc2b8b6e6433918a6b9a3566483b743dcd229da1e974be9b5f259db3aad7/billiard-4.2.3.tar.gz", hash = "sha256:96486f0885afc38219d02d5f0ccd5bec8226a414b834ab244008cbb0025b8dcb", size = 156450, upload-time = "2025-11-16T17:47:30.281Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/a6/80/ef8dff49aae0e4430f81842f7403e14e0ca59db7bbaf7af41245b67c6b25/billiard-4.2.2-py3-none-any.whl", hash = "sha256:4bc05dcf0d1cc6addef470723aac2a6232f3c7ed7475b0b580473a9145829457", size = 86896, upload-time = "2025-09-20T14:44:39.157Z" },
|
{ url = "https://files.pythonhosted.org/packages/b3/cc/38b6f87170908bd8aaf9e412b021d17e85f690abe00edf50192f1a4566b9/billiard-4.2.3-py3-none-any.whl", hash = "sha256:989e9b688e3abf153f307b68a1328dfacfb954e30a4f920005654e276c69236b", size = 87042, upload-time = "2025-11-16T17:47:29.005Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1360,6 +1360,7 @@ dependencies = [
|
||||||
{ name = "djangorestframework-stubs" },
|
{ name = "djangorestframework-stubs" },
|
||||||
{ name = "djangorestframework-xml" },
|
{ name = "djangorestframework-xml" },
|
||||||
{ name = "djangorestframework-yaml" },
|
{ name = "djangorestframework-yaml" },
|
||||||
|
{ name = "docutils" },
|
||||||
{ name = "drf-spectacular", extra = ["sidecar"] },
|
{ name = "drf-spectacular", extra = ["sidecar"] },
|
||||||
{ name = "drf-spectacular-websocket" },
|
{ name = "drf-spectacular-websocket" },
|
||||||
{ name = "elasticsearch-dsl" },
|
{ name = "elasticsearch-dsl" },
|
||||||
|
|
@ -1467,6 +1468,7 @@ requires-dist = [
|
||||||
{ name = "djangorestframework-stubs", specifier = "==3.16.5" },
|
{ name = "djangorestframework-stubs", specifier = "==3.16.5" },
|
||||||
{ name = "djangorestframework-xml", specifier = "==2.0.0" },
|
{ name = "djangorestframework-xml", specifier = "==2.0.0" },
|
||||||
{ name = "djangorestframework-yaml", specifier = "==2.0.0" },
|
{ name = "djangorestframework-yaml", specifier = "==2.0.0" },
|
||||||
|
{ name = "docutils", specifier = ">=0.21.2" },
|
||||||
{ name = "drf-spectacular", extras = ["sidecar"], specifier = "==0.29.0" },
|
{ name = "drf-spectacular", extras = ["sidecar"], specifier = "==0.29.0" },
|
||||||
{ name = "drf-spectacular-websocket", specifier = ">=1.3.1" },
|
{ name = "drf-spectacular-websocket", specifier = ">=1.3.1" },
|
||||||
{ name = "elasticsearch-dsl", specifier = "==8.18.0" },
|
{ name = "elasticsearch-dsl", specifier = "==8.18.0" },
|
||||||
|
|
@ -2599,43 +2601,43 @@ wheels = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "numpy"
|
name = "numpy"
|
||||||
version = "2.3.4"
|
version = "2.3.5"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/b5/f4/098d2270d52b41f1bd7db9fc288aaa0400cb48c2a3e2af6fa365d9720947/numpy-2.3.4.tar.gz", hash = "sha256:a7d018bfedb375a8d979ac758b120ba846a7fe764911a64465fd87b8729f4a6a", size = 20582187, upload-time = "2025-10-15T16:18:11.77Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/76/65/21b3bc86aac7b8f2862db1e808f1ea22b028e30a225a34a5ede9bf8678f2/numpy-2.3.5.tar.gz", hash = "sha256:784db1dcdab56bf0517743e746dfb0f885fc68d948aba86eeec2cba234bdf1c0", size = 20584950, upload-time = "2025-11-16T22:52:42.067Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/96/7a/02420400b736f84317e759291b8edaeee9dc921f72b045475a9cbdb26b17/numpy-2.3.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ef1b5a3e808bc40827b5fa2c8196151a4c5abe110e1726949d7abddfe5c7ae11", size = 20957727, upload-time = "2025-10-15T16:15:44.9Z" },
|
{ url = "https://files.pythonhosted.org/packages/44/37/e669fe6cbb2b96c62f6bbedc6a81c0f3b7362f6a59230b23caa673a85721/numpy-2.3.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:74ae7b798248fe62021dbf3c914245ad45d1a6b0cb4a29ecb4b31d0bfbc4cc3e", size = 16733873, upload-time = "2025-11-16T22:49:49.84Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/18/90/a014805d627aa5750f6f0e878172afb6454552da929144b3c07fcae1bb13/numpy-2.3.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c2f91f496a87235c6aaf6d3f3d89b17dba64996abadccb289f48456cff931ca9", size = 14187262, upload-time = "2025-10-15T16:15:47.761Z" },
|
{ url = "https://files.pythonhosted.org/packages/c5/65/df0db6c097892c9380851ab9e44b52d4f7ba576b833996e0080181c0c439/numpy-2.3.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ee3888d9ff7c14604052b2ca5535a30216aa0a58e948cdd3eeb8d3415f638769", size = 12259838, upload-time = "2025-11-16T22:49:52.863Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c7/e4/0a94b09abe89e500dc748e7515f21a13e30c5c3fe3396e6d4ac108c25fca/numpy-2.3.4-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:f77e5b3d3da652b474cc80a14084927a5e86a5eccf54ca8ca5cbd697bf7f2667", size = 5115992, upload-time = "2025-10-15T16:15:50.144Z" },
|
{ url = "https://files.pythonhosted.org/packages/5b/e1/1ee06e70eb2136797abe847d386e7c0e830b67ad1d43f364dd04fa50d338/numpy-2.3.5-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:612a95a17655e213502f60cfb9bf9408efdc9eb1d5f50535cc6eb365d11b42b5", size = 5088378, upload-time = "2025-11-16T22:49:55.055Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/88/dd/db77c75b055c6157cbd4f9c92c4458daef0dd9cbe6d8d2fe7f803cb64c37/numpy-2.3.4-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:8ab1c5f5ee40d6e01cbe96de5863e39b215a4d24e7d007cad56c7184fdf4aeef", size = 6648672, upload-time = "2025-10-15T16:15:52.442Z" },
|
{ url = "https://files.pythonhosted.org/packages/6d/9c/1ca85fb86708724275103b81ec4cf1ac1d08f465368acfc8da7ab545bdae/numpy-2.3.5-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3101e5177d114a593d79dd79658650fe28b5a0d8abeb8ce6f437c0e6df5be1a4", size = 6628559, upload-time = "2025-11-16T22:49:57.371Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e1/e6/e31b0d713719610e406c0ea3ae0d90760465b086da8783e2fd835ad59027/numpy-2.3.4-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:77b84453f3adcb994ddbd0d1c5d11db2d6bda1a2b7fd5ac5bd4649d6f5dc682e", size = 14284156, upload-time = "2025-10-15T16:15:54.351Z" },
|
{ url = "https://files.pythonhosted.org/packages/74/78/fcd41e5a0ce4f3f7b003da85825acddae6d7ecb60cf25194741b036ca7d6/numpy-2.3.5-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b973c57ff8e184109db042c842423ff4f60446239bd585a5131cc47f06f789d", size = 14250702, upload-time = "2025-11-16T22:49:59.632Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/f9/58/30a85127bfee6f108282107caf8e06a1f0cc997cb6b52cdee699276fcce4/numpy-2.3.4-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4121c5beb58a7f9e6dfdee612cb24f4df5cd4db6e8261d7f4d7450a997a65d6a", size = 16641271, upload-time = "2025-10-15T16:15:56.67Z" },
|
{ url = "https://files.pythonhosted.org/packages/b6/23/2a1b231b8ff672b4c450dac27164a8b2ca7d9b7144f9c02d2396518352eb/numpy-2.3.5-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0d8163f43acde9a73c2a33605353a4f1bc4798745a8b1d73183b28e5b435ae28", size = 16606086, upload-time = "2025-11-16T22:50:02.127Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/06/f2/2e06a0f2adf23e3ae29283ad96959267938d0efd20a2e25353b70065bfec/numpy-2.3.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:65611ecbb00ac9846efe04db15cbe6186f562f6bb7e5e05f077e53a599225d16", size = 16059531, upload-time = "2025-10-15T16:15:59.412Z" },
|
{ url = "https://files.pythonhosted.org/packages/a0/c5/5ad26fbfbe2012e190cc7d5003e4d874b88bb18861d0829edc140a713021/numpy-2.3.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:51c1e14eb1e154ebd80e860722f9e6ed6ec89714ad2db2d3aa33c31d7c12179b", size = 16025985, upload-time = "2025-11-16T22:50:04.536Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b0/e7/b106253c7c0d5dc352b9c8fab91afd76a93950998167fa3e5afe4ef3a18f/numpy-2.3.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dabc42f9c6577bcc13001b8810d300fe814b4cfbe8a92c873f269484594f9786", size = 18578983, upload-time = "2025-10-15T16:16:01.804Z" },
|
{ url = "https://files.pythonhosted.org/packages/d2/fa/dd48e225c46c819288148d9d060b047fd2a6fb1eb37eae25112ee4cb4453/numpy-2.3.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b46b4ec24f7293f23adcd2d146960559aaf8020213de8ad1909dba6c013bf89c", size = 18542976, upload-time = "2025-11-16T22:50:07.557Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/73/e3/04ecc41e71462276ee867ccbef26a4448638eadecf1bc56772c9ed6d0255/numpy-2.3.4-cp312-cp312-win32.whl", hash = "sha256:a49d797192a8d950ca59ee2d0337a4d804f713bb5c3c50e8db26d49666e351dc", size = 6291380, upload-time = "2025-10-15T16:16:03.938Z" },
|
{ url = "https://files.pythonhosted.org/packages/05/79/ccbd23a75862d95af03d28b5c6901a1b7da4803181513d52f3b86ed9446e/numpy-2.3.5-cp312-cp312-win32.whl", hash = "sha256:3997b5b3c9a771e157f9aae01dd579ee35ad7109be18db0e85dbdbe1de06e952", size = 6285274, upload-time = "2025-11-16T22:50:10.746Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/3d/a8/566578b10d8d0e9955b1b6cd5db4e9d4592dd0026a941ff7994cedda030a/numpy-2.3.4-cp312-cp312-win_amd64.whl", hash = "sha256:985f1e46358f06c2a09921e8921e2c98168ed4ae12ccd6e5e87a4f1857923f32", size = 12787999, upload-time = "2025-10-15T16:16:05.801Z" },
|
{ url = "https://files.pythonhosted.org/packages/2d/57/8aeaf160312f7f489dea47ab61e430b5cb051f59a98ae68b7133ce8fa06a/numpy-2.3.5-cp312-cp312-win_amd64.whl", hash = "sha256:86945f2ee6d10cdfd67bcb4069c1662dd711f7e2a4343db5cecec06b87cf31aa", size = 12782922, upload-time = "2025-11-16T22:50:12.811Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/58/22/9c903a957d0a8071b607f5b1bff0761d6e608b9a965945411f867d515db1/numpy-2.3.4-cp312-cp312-win_arm64.whl", hash = "sha256:4635239814149e06e2cb9db3dd584b2fa64316c96f10656983b8026a82e6e4db", size = 10197412, upload-time = "2025-10-15T16:16:07.854Z" },
|
{ url = "https://files.pythonhosted.org/packages/78/a6/aae5cc2ca78c45e64b9ef22f089141d661516856cf7c8a54ba434576900d/numpy-2.3.5-cp312-cp312-win_arm64.whl", hash = "sha256:f28620fe26bee16243be2b7b874da327312240a7cdc38b769a697578d2100013", size = 10194667, upload-time = "2025-11-16T22:50:16.16Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/57/7e/b72610cc91edf138bc588df5150957a4937221ca6058b825b4725c27be62/numpy-2.3.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c090d4860032b857d94144d1a9976b8e36709e40386db289aaf6672de2a81966", size = 20950335, upload-time = "2025-10-15T16:16:10.304Z" },
|
{ url = "https://files.pythonhosted.org/packages/db/69/9cde09f36da4b5a505341180a3f2e6fadc352fd4d2b7096ce9778db83f1a/numpy-2.3.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d0f23b44f57077c1ede8c5f26b30f706498b4862d3ff0a7298b8411dd2f043ff", size = 16728251, upload-time = "2025-11-16T22:50:19.013Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/3e/46/bdd3370dcea2f95ef14af79dbf81e6927102ddf1cc54adc0024d61252fd9/numpy-2.3.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a13fc473b6db0be619e45f11f9e81260f7302f8d180c49a22b6e6120022596b3", size = 14179878, upload-time = "2025-10-15T16:16:12.595Z" },
|
{ url = "https://files.pythonhosted.org/packages/79/fb/f505c95ceddd7027347b067689db71ca80bd5ecc926f913f1a23e65cf09b/numpy-2.3.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:aa5bc7c5d59d831d9773d1170acac7893ce3a5e130540605770ade83280e7188", size = 12254652, upload-time = "2025-11-16T22:50:21.487Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ac/01/5a67cb785bda60f45415d09c2bc245433f1c68dd82eef9c9002c508b5a65/numpy-2.3.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:3634093d0b428e6c32c3a69b78e554f0cd20ee420dcad5a9f3b2a63762ce4197", size = 5108673, upload-time = "2025-10-15T16:16:14.877Z" },
|
{ url = "https://files.pythonhosted.org/packages/78/da/8c7738060ca9c31b30e9301ee0cf6c5ffdbf889d9593285a1cead337f9a5/numpy-2.3.5-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:ccc933afd4d20aad3c00bcef049cb40049f7f196e0397f1109dba6fed63267b0", size = 5083172, upload-time = "2025-11-16T22:50:24.562Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c2/cd/8428e23a9fcebd33988f4cb61208fda832800ca03781f471f3727a820704/numpy-2.3.4-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:043885b4f7e6e232d7df4f51ffdef8c36320ee9d5f227b380ea636722c7ed12e", size = 6641438, upload-time = "2025-10-15T16:16:16.805Z" },
|
{ url = "https://files.pythonhosted.org/packages/a4/b4/ee5bb2537fb9430fd2ef30a616c3672b991a4129bb1c7dcc42aa0abbe5d7/numpy-2.3.5-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:afaffc4393205524af9dfa400fa250143a6c3bc646c08c9f5e25a9f4b4d6a903", size = 6622990, upload-time = "2025-11-16T22:50:26.47Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/3e/d1/913fe563820f3c6b079f992458f7331278dcd7ba8427e8e745af37ddb44f/numpy-2.3.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4ee6a571d1e4f0ea6d5f22d6e5fbd6ed1dc2b18542848e1e7301bd190500c9d7", size = 14281290, upload-time = "2025-10-15T16:16:18.764Z" },
|
{ url = "https://files.pythonhosted.org/packages/95/03/dc0723a013c7d7c19de5ef29e932c3081df1c14ba582b8b86b5de9db7f0f/numpy-2.3.5-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c75442b2209b8470d6d5d8b1c25714270686f14c749028d2199c54e29f20b4d", size = 14248902, upload-time = "2025-11-16T22:50:28.861Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/9e/7e/7d306ff7cb143e6d975cfa7eb98a93e73495c4deabb7d1b5ecf09ea0fd69/numpy-2.3.4-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fc8a63918b04b8571789688b2780ab2b4a33ab44bfe8ccea36d3eba51228c953", size = 16636543, upload-time = "2025-10-15T16:16:21.072Z" },
|
{ url = "https://files.pythonhosted.org/packages/f5/10/ca162f45a102738958dcec8023062dad0cbc17d1ab99d68c4e4a6c45fb2b/numpy-2.3.5-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11e06aa0af8c0f05104d56450d6093ee639e15f24ecf62d417329d06e522e017", size = 16597430, upload-time = "2025-11-16T22:50:31.56Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/47/6a/8cfc486237e56ccfb0db234945552a557ca266f022d281a2f577b98e955c/numpy-2.3.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:40cc556d5abbc54aabe2b1ae287042d7bdb80c08edede19f0c0afb36ae586f37", size = 16056117, upload-time = "2025-10-15T16:16:23.369Z" },
|
{ url = "https://files.pythonhosted.org/packages/2a/51/c1e29be863588db58175175f057286900b4b3327a1351e706d5e0f8dd679/numpy-2.3.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ed89927b86296067b4f81f108a2271d8926467a8868e554eaf370fc27fa3ccaf", size = 16024551, upload-time = "2025-11-16T22:50:34.242Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b1/0e/42cb5e69ea901e06ce24bfcc4b5664a56f950a70efdcf221f30d9615f3f3/numpy-2.3.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ecb63014bb7f4ce653f8be7f1df8cbc6093a5a2811211770f6606cc92b5a78fd", size = 18577788, upload-time = "2025-10-15T16:16:27.496Z" },
|
{ url = "https://files.pythonhosted.org/packages/83/68/8236589d4dbb87253d28259d04d9b814ec0ecce7cb1c7fed29729f4c3a78/numpy-2.3.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51c55fe3451421f3a6ef9a9c1439e82101c57a2c9eab9feb196a62b1a10b58ce", size = 18533275, upload-time = "2025-11-16T22:50:37.651Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/86/92/41c3d5157d3177559ef0a35da50f0cda7fa071f4ba2306dd36818591a5bc/numpy-2.3.4-cp313-cp313-win32.whl", hash = "sha256:e8370eb6925bb8c1c4264fec52b0384b44f675f191df91cbe0140ec9f0955646", size = 6282620, upload-time = "2025-10-15T16:16:29.811Z" },
|
{ url = "https://files.pythonhosted.org/packages/40/56/2932d75b6f13465239e3b7b7e511be27f1b8161ca2510854f0b6e521c395/numpy-2.3.5-cp313-cp313-win32.whl", hash = "sha256:1978155dd49972084bd6ef388d66ab70f0c323ddee6f693d539376498720fb7e", size = 6277637, upload-time = "2025-11-16T22:50:40.11Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/09/97/fd421e8bc50766665ad35536c2bb4ef916533ba1fdd053a62d96cc7c8b95/numpy-2.3.4-cp313-cp313-win_amd64.whl", hash = "sha256:56209416e81a7893036eea03abcb91c130643eb14233b2515c90dcac963fe99d", size = 12784672, upload-time = "2025-10-15T16:16:31.589Z" },
|
{ url = "https://files.pythonhosted.org/packages/0c/88/e2eaa6cffb115b85ed7c7c87775cb8bcf0816816bc98ca8dbfa2ee33fe6e/numpy-2.3.5-cp313-cp313-win_amd64.whl", hash = "sha256:00dc4e846108a382c5869e77c6ed514394bdeb3403461d25a829711041217d5b", size = 12779090, upload-time = "2025-11-16T22:50:42.503Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ad/df/5474fb2f74970ca8eb978093969b125a84cc3d30e47f82191f981f13a8a0/numpy-2.3.4-cp313-cp313-win_arm64.whl", hash = "sha256:a700a4031bc0fd6936e78a752eefb79092cecad2599ea9c8039c548bc097f9bc", size = 10196702, upload-time = "2025-10-15T16:16:33.902Z" },
|
{ url = "https://files.pythonhosted.org/packages/8f/88/3f41e13a44ebd4034ee17baa384acac29ba6a4fcc2aca95f6f08ca0447d1/numpy-2.3.5-cp313-cp313-win_arm64.whl", hash = "sha256:0472f11f6ec23a74a906a00b48a4dcf3849209696dff7c189714511268d103ae", size = 10194710, upload-time = "2025-11-16T22:50:44.971Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/11/83/66ac031464ec1767ea3ed48ce40f615eb441072945e98693bec0bcd056cc/numpy-2.3.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:86966db35c4040fdca64f0816a1c1dd8dbd027d90fca5a57e00e1ca4cd41b879", size = 21049003, upload-time = "2025-10-15T16:16:36.101Z" },
|
{ url = "https://files.pythonhosted.org/packages/13/cb/71744144e13389d577f867f745b7df2d8489463654a918eea2eeb166dfc9/numpy-2.3.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:414802f3b97f3c1eef41e530aaba3b3c1620649871d8cb38c6eaff034c2e16bd", size = 16827292, upload-time = "2025-11-16T22:50:47.715Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/5f/99/5b14e0e686e61371659a1d5bebd04596b1d72227ce36eed121bb0aeab798/numpy-2.3.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:838f045478638b26c375ee96ea89464d38428c69170360b23a1a50fa4baa3562", size = 14302980, upload-time = "2025-10-15T16:16:39.124Z" },
|
{ url = "https://files.pythonhosted.org/packages/71/80/ba9dc6f2a4398e7f42b708a7fdc841bb638d353be255655498edbf9a15a8/numpy-2.3.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5ee6609ac3604fa7780e30a03e5e241a7956f8e2fcfe547d51e3afa5247ac47f", size = 12378897, upload-time = "2025-11-16T22:50:51.327Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/2c/44/e9486649cd087d9fc6920e3fc3ac2aba10838d10804b1e179fb7cbc4e634/numpy-2.3.4-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d7315ed1dab0286adca467377c8381cd748f3dc92235f22a7dfc42745644a96a", size = 5231472, upload-time = "2025-10-15T16:16:41.168Z" },
|
{ url = "https://files.pythonhosted.org/packages/2e/6d/db2151b9f64264bcceccd51741aa39b50150de9b602d98ecfe7e0c4bff39/numpy-2.3.5-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:86d835afea1eaa143012a2d7a3f45a3adce2d7adc8b4961f0b362214d800846a", size = 5207391, upload-time = "2025-11-16T22:50:54.542Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/3e/51/902b24fa8887e5fe2063fd61b1895a476d0bbf46811ab0c7fdf4bd127345/numpy-2.3.4-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:84f01a4d18b2cc4ade1814a08e5f3c907b079c847051d720fad15ce37aa930b6", size = 6739342, upload-time = "2025-10-15T16:16:43.777Z" },
|
{ url = "https://files.pythonhosted.org/packages/80/ae/429bacace5ccad48a14c4ae5332f6aa8ab9f69524193511d60ccdfdc65fa/numpy-2.3.5-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:30bc11310e8153ca664b14c5f1b73e94bd0503681fcf136a163de856f3a50139", size = 6721275, upload-time = "2025-11-16T22:50:56.794Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/34/f1/4de9586d05b1962acdcdb1dc4af6646361a643f8c864cef7c852bf509740/numpy-2.3.4-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:817e719a868f0dacde4abdfc5c1910b301877970195db9ab6a5e2c4bd5b121f7", size = 14354338, upload-time = "2025-10-15T16:16:46.081Z" },
|
{ url = "https://files.pythonhosted.org/packages/74/5b/1919abf32d8722646a38cd527bc3771eb229a32724ee6ba340ead9b92249/numpy-2.3.5-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1062fde1dcf469571705945b0f221b73928f34a20c904ffb45db101907c3454e", size = 14306855, upload-time = "2025-11-16T22:50:59.208Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/1f/06/1c16103b425de7969d5a76bdf5ada0804b476fed05d5f9e17b777f1cbefd/numpy-2.3.4-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85e071da78d92a214212cacea81c6da557cab307f2c34b5f85b628e94803f9c0", size = 16702392, upload-time = "2025-10-15T16:16:48.455Z" },
|
{ url = "https://files.pythonhosted.org/packages/a5/87/6831980559434973bebc30cd9c1f21e541a0f2b0c280d43d3afd909b66d0/numpy-2.3.5-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce581db493ea1a96c0556360ede6607496e8bf9b3a8efa66e06477267bc831e9", size = 16657359, upload-time = "2025-11-16T22:51:01.991Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/34/b2/65f4dc1b89b5322093572b6e55161bb42e3e0487067af73627f795cc9d47/numpy-2.3.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2ec646892819370cf3558f518797f16597b4e4669894a2ba712caccc9da53f1f", size = 16134998, upload-time = "2025-10-15T16:16:51.114Z" },
|
{ url = "https://files.pythonhosted.org/packages/dd/91/c797f544491ee99fd00495f12ebb7802c440c1915811d72ac5b4479a3356/numpy-2.3.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:cc8920d2ec5fa99875b670bb86ddeb21e295cb07aa331810d9e486e0b969d946", size = 16093374, upload-time = "2025-11-16T22:51:05.291Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d4/11/94ec578896cdb973aaf56425d6c7f2aff4186a5c00fac15ff2ec46998b46/numpy-2.3.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:035796aaaddfe2f9664b9a9372f089cfc88bd795a67bd1bfe15e6e770934cf64", size = 18651574, upload-time = "2025-10-15T16:16:53.429Z" },
|
{ url = "https://files.pythonhosted.org/packages/74/a6/54da03253afcbe7a72785ec4da9c69fb7a17710141ff9ac5fcb2e32dbe64/numpy-2.3.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:9ee2197ef8c4f0dfe405d835f3b6a14f5fee7782b5de51ba06fb65fc9b36e9f1", size = 18594587, upload-time = "2025-11-16T22:51:08.585Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/62/b7/7efa763ab33dbccf56dade36938a77345ce8e8192d6b39e470ca25ff3cd0/numpy-2.3.4-cp313-cp313t-win32.whl", hash = "sha256:fea80f4f4cf83b54c3a051f2f727870ee51e22f0248d3114b8e755d160b38cfb", size = 6413135, upload-time = "2025-10-15T16:16:55.992Z" },
|
{ url = "https://files.pythonhosted.org/packages/80/e9/aff53abbdd41b0ecca94285f325aff42357c6b5abc482a3fcb4994290b18/numpy-2.3.5-cp313-cp313t-win32.whl", hash = "sha256:70b37199913c1bd300ff6e2693316c6f869c7ee16378faf10e4f5e3275b299c3", size = 6405940, upload-time = "2025-11-16T22:51:11.541Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/43/70/aba4c38e8400abcc2f345e13d972fb36c26409b3e644366db7649015f291/numpy-2.3.4-cp313-cp313t-win_amd64.whl", hash = "sha256:15eea9f306b98e0be91eb344a94c0e630689ef302e10c2ce5f7e11905c704f9c", size = 12928582, upload-time = "2025-10-15T16:16:57.943Z" },
|
{ url = "https://files.pythonhosted.org/packages/d5/81/50613fec9d4de5480de18d4f8ef59ad7e344d497edbef3cfd80f24f98461/numpy-2.3.5-cp313-cp313t-win_amd64.whl", hash = "sha256:b501b5fa195cc9e24fe102f21ec0a44dffc231d2af79950b451e0d99cea02234", size = 12920341, upload-time = "2025-11-16T22:51:14.312Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/67/63/871fad5f0073fc00fbbdd7232962ea1ac40eeaae2bba66c76214f7954236/numpy-2.3.4-cp313-cp313t-win_arm64.whl", hash = "sha256:b6c231c9c2fadbae4011ca5e7e83e12dc4a5072f1a1d85a0a7b3ed754d145a40", size = 10266691, upload-time = "2025-10-15T16:17:00.048Z" },
|
{ url = "https://files.pythonhosted.org/packages/bb/ab/08fd63b9a74303947f34f0bd7c5903b9c5532c2d287bead5bdf4c556c486/numpy-2.3.5-cp313-cp313t-win_arm64.whl", hash = "sha256:a80afd79f45f3c4a7d341f13acbe058d1ca8ac017c165d3fa0d3de6bc1a079d7", size = 10262507, upload-time = "2025-11-16T22:51:16.846Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -3450,54 +3452,54 @@ wheels = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rpds-py"
|
name = "rpds-py"
|
||||||
version = "0.28.0"
|
version = "0.29.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/48/dc/95f074d43452b3ef5d06276696ece4b3b5d696e7c9ad7173c54b1390cd70/rpds_py-0.28.0.tar.gz", hash = "sha256:abd4df20485a0983e2ca334a216249b6186d6e3c1627e106651943dbdb791aea", size = 27419, upload-time = "2025-10-22T22:24:29.327Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/98/33/23b3b3419b6a3e0f559c7c0d2ca8fc1b9448382b25245033788785921332/rpds_py-0.29.0.tar.gz", hash = "sha256:fe55fe686908f50154d1dc599232016e50c243b438c3b7432f24e2895b0e5359", size = 69359, upload-time = "2025-11-16T14:50:39.532Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/b8/5c/6c3936495003875fe7b14f90ea812841a08fca50ab26bd840e924097d9c8/rpds_py-0.28.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:6b4f28583a4f247ff60cd7bdda83db8c3f5b05a7a82ff20dd4b078571747708f", size = 366439, upload-time = "2025-10-22T22:22:04.525Z" },
|
{ url = "https://files.pythonhosted.org/packages/3c/50/bc0e6e736d94e420df79be4deb5c9476b63165c87bb8f19ef75d100d21b3/rpds_py-0.29.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a0891cfd8db43e085c0ab93ab7e9b0c8fee84780d436d3b266b113e51e79f954", size = 376000, upload-time = "2025-11-16T14:48:19.141Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/56/f9/a0f1ca194c50aa29895b442771f036a25b6c41a35e4f35b1a0ea713bedae/rpds_py-0.28.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d678e91b610c29c4b3d52a2c148b641df2b4676ffe47c59f6388d58b99cdc424", size = 348170, upload-time = "2025-10-22T22:22:06.397Z" },
|
{ url = "https://files.pythonhosted.org/packages/3e/3a/46676277160f014ae95f24de53bed0e3b7ea66c235e7de0b9df7bd5d68ba/rpds_py-0.29.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3897924d3f9a0361472d884051f9a2460358f9a45b1d85a39a158d2f8f1ad71c", size = 360575, upload-time = "2025-11-16T14:48:20.443Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/18/ea/42d243d3a586beb72c77fa5def0487daf827210069a95f36328e869599ea/rpds_py-0.28.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e819e0e37a44a78e1383bf1970076e2ccc4dc8c2bbaa2f9bd1dc987e9afff628", size = 378838, upload-time = "2025-10-22T22:22:07.932Z" },
|
{ url = "https://files.pythonhosted.org/packages/75/ba/411d414ed99ea1afdd185bbabeeaac00624bd1e4b22840b5e9967ade6337/rpds_py-0.29.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a21deb8e0d1571508c6491ce5ea5e25669b1dd4adf1c9d64b6314842f708b5d", size = 392159, upload-time = "2025-11-16T14:48:22.12Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e7/78/3de32e18a94791af8f33601402d9d4f39613136398658412a4e0b3047327/rpds_py-0.28.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5ee514e0f0523db5d3fb171f397c54875dbbd69760a414dccf9d4d7ad628b5bd", size = 393299, upload-time = "2025-10-22T22:22:09.435Z" },
|
{ url = "https://files.pythonhosted.org/packages/8f/b1/e18aa3a331f705467a48d0296778dc1fea9d7f6cf675bd261f9a846c7e90/rpds_py-0.29.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9efe71687d6427737a0a2de9ca1c0a216510e6cd08925c44162be23ed7bed2d5", size = 410602, upload-time = "2025-11-16T14:48:23.563Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/13/7e/4bdb435afb18acea2eb8a25ad56b956f28de7c59f8a1d32827effa0d4514/rpds_py-0.28.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5f3fa06d27fdcee47f07a39e02862da0100cb4982508f5ead53ec533cd5fe55e", size = 518000, upload-time = "2025-10-22T22:22:11.326Z" },
|
{ url = "https://files.pythonhosted.org/packages/2f/6c/04f27f0c9f2299274c76612ac9d2c36c5048bb2c6c2e52c38c60bf3868d9/rpds_py-0.29.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:40f65470919dc189c833e86b2c4bd21bd355f98436a2cef9e0a9a92aebc8e57e", size = 515808, upload-time = "2025-11-16T14:48:24.949Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/31/d0/5f52a656875cdc60498ab035a7a0ac8f399890cc1ee73ebd567bac4e39ae/rpds_py-0.28.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:46959ef2e64f9e4a41fc89aa20dbca2b85531f9a72c21099a3360f35d10b0d5a", size = 408746, upload-time = "2025-10-22T22:22:13.143Z" },
|
{ url = "https://files.pythonhosted.org/packages/83/56/a8412aa464fb151f8bc0d91fb0bb888adc9039bd41c1c6ba8d94990d8cf8/rpds_py-0.29.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:def48ff59f181130f1a2cb7c517d16328efac3ec03951cca40c1dc2049747e83", size = 416015, upload-time = "2025-11-16T14:48:26.782Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/3e/cd/49ce51767b879cde77e7ad9fae164ea15dce3616fe591d9ea1df51152706/rpds_py-0.28.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8455933b4bcd6e83fde3fefc987a023389c4b13f9a58c8d23e4b3f6d13f78c84", size = 386379, upload-time = "2025-10-22T22:22:14.602Z" },
|
{ url = "https://files.pythonhosted.org/packages/04/4c/f9b8a05faca3d9e0a6397c90d13acb9307c9792b2bff621430c58b1d6e76/rpds_py-0.29.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad7bd570be92695d89285a4b373006930715b78d96449f686af422debb4d3949", size = 395325, upload-time = "2025-11-16T14:48:28.055Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/6a/99/e4e1e1ee93a98f72fc450e36c0e4d99c35370220e815288e3ecd2ec36a2a/rpds_py-0.28.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:ad50614a02c8c2962feebe6012b52f9802deec4263946cddea37aaf28dd25a66", size = 401280, upload-time = "2025-10-22T22:22:16.063Z" },
|
{ url = "https://files.pythonhosted.org/packages/34/60/869f3bfbf8ed7b54f1ad9a5543e0fdffdd40b5a8f587fe300ee7b4f19340/rpds_py-0.29.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:5a572911cd053137bbff8e3a52d31c5d2dba51d3a67ad902629c70185f3f2181", size = 410160, upload-time = "2025-11-16T14:48:29.338Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/61/35/e0c6a57488392a8b319d2200d03dad2b29c0db9996f5662c3b02d0b86c02/rpds_py-0.28.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e5deca01b271492553fdb6c7fd974659dce736a15bae5dad7ab8b93555bceb28", size = 412365, upload-time = "2025-10-22T22:22:17.504Z" },
|
{ url = "https://files.pythonhosted.org/packages/91/aa/e5b496334e3aba4fe4c8a80187b89f3c1294c5c36f2a926da74338fa5a73/rpds_py-0.29.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d583d4403bcbf10cffc3ab5cee23d7643fcc960dff85973fd3c2d6c86e8dbb0c", size = 425309, upload-time = "2025-11-16T14:48:30.691Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ff/6a/841337980ea253ec797eb084665436007a1aad0faac1ba097fb906c5f69c/rpds_py-0.28.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:735f8495a13159ce6a0d533f01e8674cec0c57038c920495f87dcb20b3ddb48a", size = 559573, upload-time = "2025-10-22T22:22:19.108Z" },
|
{ url = "https://files.pythonhosted.org/packages/85/68/4e24a34189751ceb6d66b28f18159922828dd84155876551f7ca5b25f14f/rpds_py-0.29.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:070befbb868f257d24c3bb350dbd6e2f645e83731f31264b19d7231dd5c396c7", size = 574644, upload-time = "2025-11-16T14:48:31.964Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e7/5e/64826ec58afd4c489731f8b00729c5f6afdb86f1df1df60bfede55d650bb/rpds_py-0.28.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:961ca621ff10d198bbe6ba4957decca61aa2a0c56695384c1d6b79bf61436df5", size = 583973, upload-time = "2025-10-22T22:22:20.768Z" },
|
{ url = "https://files.pythonhosted.org/packages/8c/cf/474a005ea4ea9c3b4f17b6108b6b13cebfc98ebaff11d6e1b193204b3a93/rpds_py-0.29.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:fc935f6b20b0c9f919a8ff024739174522abd331978f750a74bb68abd117bd19", size = 601605, upload-time = "2025-11-16T14:48:33.252Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b6/ee/44d024b4843f8386a4eeaa4c171b3d31d55f7177c415545fd1a24c249b5d/rpds_py-0.28.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2374e16cc9131022e7d9a8f8d65d261d9ba55048c78f3b6e017971a4f5e6353c", size = 553800, upload-time = "2025-10-22T22:22:22.25Z" },
|
{ url = "https://files.pythonhosted.org/packages/f4/b1/c56f6a9ab8c5f6bb5c65c4b5f8229167a3a525245b0773f2c0896686b64e/rpds_py-0.29.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8c5a8ecaa44ce2d8d9d20a68a2483a74c07f05d72e94a4dff88906c8807e77b0", size = 564593, upload-time = "2025-11-16T14:48:34.643Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/7d/89/33e675dccff11a06d4d85dbb4d1865f878d5020cbb69b2c1e7b2d3f82562/rpds_py-0.28.0-cp312-cp312-win32.whl", hash = "sha256:d15431e334fba488b081d47f30f091e5d03c18527c325386091f31718952fe08", size = 216954, upload-time = "2025-10-22T22:22:24.105Z" },
|
{ url = "https://files.pythonhosted.org/packages/b3/13/0494cecce4848f68501e0a229432620b4b57022388b071eeff95f3e1e75b/rpds_py-0.29.0-cp312-cp312-win32.whl", hash = "sha256:ba5e1aeaf8dd6d8f6caba1f5539cddda87d511331714b7b5fc908b6cfc3636b7", size = 223853, upload-time = "2025-11-16T14:48:36.419Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/af/36/45f6ebb3210887e8ee6dbf1bc710ae8400bb417ce165aaf3024b8360d999/rpds_py-0.28.0-cp312-cp312-win_amd64.whl", hash = "sha256:a410542d61fc54710f750d3764380b53bf09e8c4edbf2f9141a82aa774a04f7c", size = 227844, upload-time = "2025-10-22T22:22:25.551Z" },
|
{ url = "https://files.pythonhosted.org/packages/1f/6a/51e9aeb444a00cdc520b032a28b07e5f8dc7bc328b57760c53e7f96997b4/rpds_py-0.29.0-cp312-cp312-win_amd64.whl", hash = "sha256:b5f6134faf54b3cb83375db0f113506f8b7770785be1f95a631e7e2892101977", size = 239895, upload-time = "2025-11-16T14:48:37.956Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/57/91/f3fb250d7e73de71080f9a221d19bd6a1c1eb0d12a1ea26513f6c1052ad6/rpds_py-0.28.0-cp312-cp312-win_arm64.whl", hash = "sha256:1f0cfd1c69e2d14f8c892b893997fa9a60d890a0c8a603e88dca4955f26d1edd", size = 217624, upload-time = "2025-10-22T22:22:26.914Z" },
|
{ url = "https://files.pythonhosted.org/packages/d1/d4/8bce56cdad1ab873e3f27cb31c6a51d8f384d66b022b820525b879f8bed1/rpds_py-0.29.0-cp312-cp312-win_arm64.whl", hash = "sha256:b016eddf00dca7944721bf0cd85b6af7f6c4efaf83ee0b37c4133bd39757a8c7", size = 230321, upload-time = "2025-11-16T14:48:39.71Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d3/03/ce566d92611dfac0085c2f4b048cd53ed7c274a5c05974b882a908d540a2/rpds_py-0.28.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e9e184408a0297086f880556b6168fa927d677716f83d3472ea333b42171ee3b", size = 366235, upload-time = "2025-10-22T22:22:28.397Z" },
|
{ url = "https://files.pythonhosted.org/packages/fd/d9/c5de60d9d371bbb186c3e9bf75f4fc5665e11117a25a06a6b2e0afb7380e/rpds_py-0.29.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1585648d0760b88292eecab5181f5651111a69d90eff35d6b78aa32998886a61", size = 375710, upload-time = "2025-11-16T14:48:41.063Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/00/34/1c61da1b25592b86fd285bd7bd8422f4c9d748a7373b46126f9ae792a004/rpds_py-0.28.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:edd267266a9b0448f33dc465a97cfc5d467594b600fe28e7fa2f36450e03053a", size = 348241, upload-time = "2025-10-22T22:22:30.171Z" },
|
{ url = "https://files.pythonhosted.org/packages/b3/b3/0860cdd012291dc21272895ce107f1e98e335509ba986dd83d72658b82b9/rpds_py-0.29.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:521807963971a23996ddaf764c682b3e46459b3c58ccd79fefbe16718db43154", size = 360582, upload-time = "2025-11-16T14:48:42.423Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/fc/00/ed1e28616848c61c493a067779633ebf4b569eccaacf9ccbdc0e7cba2b9d/rpds_py-0.28.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85beb8b3f45e4e32f6802fb6cd6b17f615ef6c6a52f265371fb916fae02814aa", size = 378079, upload-time = "2025-10-22T22:22:31.644Z" },
|
{ url = "https://files.pythonhosted.org/packages/92/8a/a18c2f4a61b3407e56175f6aab6deacdf9d360191a3d6f38566e1eaf7266/rpds_py-0.29.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a8896986efaa243ab713c69e6491a4138410f0fe36f2f4c71e18bd5501e8014", size = 391172, upload-time = "2025-11-16T14:48:43.75Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/11/b2/ccb30333a16a470091b6e50289adb4d3ec656fd9951ba8c5e3aaa0746a67/rpds_py-0.28.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d2412be8d00a1b895f8ad827cc2116455196e20ed994bb704bf138fe91a42724", size = 393151, upload-time = "2025-10-22T22:22:33.453Z" },
|
{ url = "https://files.pythonhosted.org/packages/fd/49/e93354258508c50abc15cdcd5fcf7ac4117f67bb6233ad7859f75e7372a0/rpds_py-0.29.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1d24564a700ef41480a984c5ebed62b74e6ce5860429b98b1fede76049e953e6", size = 409586, upload-time = "2025-11-16T14:48:45.498Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/8c/d0/73e2217c3ee486d555cb84920597480627d8c0240ff3062005c6cc47773e/rpds_py-0.28.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cf128350d384b777da0e68796afdcebc2e9f63f0e9f242217754e647f6d32491", size = 517520, upload-time = "2025-10-22T22:22:34.949Z" },
|
{ url = "https://files.pythonhosted.org/packages/5a/8d/a27860dae1c19a6bdc901f90c81f0d581df1943355802961a57cdb5b6cd1/rpds_py-0.29.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6596b93c010d386ae46c9fba9bfc9fc5965fa8228edeac51576299182c2e31c", size = 516339, upload-time = "2025-11-16T14:48:47.308Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c4/91/23efe81c700427d0841a4ae7ea23e305654381831e6029499fe80be8a071/rpds_py-0.28.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a2036d09b363aa36695d1cc1a97b36865597f4478470b0697b5ee9403f4fe399", size = 408699, upload-time = "2025-10-22T22:22:36.584Z" },
|
{ url = "https://files.pythonhosted.org/packages/fc/ad/a75e603161e79b7110c647163d130872b271c6b28712c803c65d492100f7/rpds_py-0.29.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5cc58aac218826d054c7da7f95821eba94125d88be673ff44267bb89d12a5866", size = 416201, upload-time = "2025-11-16T14:48:48.615Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ca/ee/a324d3198da151820a326c1f988caaa4f37fc27955148a76fff7a2d787a9/rpds_py-0.28.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8e1e9be4fa6305a16be628959188e4fd5cd6f1b0e724d63c6d8b2a8adf74ea6", size = 385720, upload-time = "2025-10-22T22:22:38.014Z" },
|
{ url = "https://files.pythonhosted.org/packages/b9/42/555b4ee17508beafac135c8b450816ace5a96194ce97fefc49d58e5652ea/rpds_py-0.29.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de73e40ebc04dd5d9556f50180395322193a78ec247e637e741c1b954810f295", size = 395095, upload-time = "2025-11-16T14:48:50.027Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/19/ad/e68120dc05af8b7cab4a789fccd8cdcf0fe7e6581461038cc5c164cd97d2/rpds_py-0.28.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:0a403460c9dd91a7f23fc3188de6d8977f1d9603a351d5db6cf20aaea95b538d", size = 401096, upload-time = "2025-10-22T22:22:39.869Z" },
|
{ url = "https://files.pythonhosted.org/packages/cd/f0/c90b671b9031e800ec45112be42ea9f027f94f9ac25faaac8770596a16a1/rpds_py-0.29.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:295ce5ac7f0cf69a651ea75c8f76d02a31f98e5698e82a50a5f4d4982fbbae3b", size = 410077, upload-time = "2025-11-16T14:48:51.515Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/99/90/c1e070620042459d60df6356b666bb1f62198a89d68881816a7ed121595a/rpds_py-0.28.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d7366b6553cdc805abcc512b849a519167db8f5e5c3472010cd1228b224265cb", size = 411465, upload-time = "2025-10-22T22:22:41.395Z" },
|
{ url = "https://files.pythonhosted.org/packages/3d/80/9af8b640b81fe21e6f718e9dec36c0b5f670332747243130a5490f292245/rpds_py-0.29.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1ea59b23ea931d494459c8338056fe7d93458c0bf3ecc061cd03916505369d55", size = 424548, upload-time = "2025-11-16T14:48:53.237Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/68/61/7c195b30d57f1b8d5970f600efee72a4fad79ec829057972e13a0370fd24/rpds_py-0.28.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5b43c6a3726efd50f18d8120ec0551241c38785b68952d240c45ea553912ac41", size = 558832, upload-time = "2025-10-22T22:22:42.871Z" },
|
{ url = "https://files.pythonhosted.org/packages/e4/0b/b5647446e991736e6a495ef510e6710df91e880575a586e763baeb0aa770/rpds_py-0.29.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f49d41559cebd608042fdcf54ba597a4a7555b49ad5c1c0c03e0af82692661cd", size = 573661, upload-time = "2025-11-16T14:48:54.769Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b0/3d/06f3a718864773f69941d4deccdf18e5e47dd298b4628062f004c10f3b34/rpds_py-0.28.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0cb7203c7bc69d7c1585ebb33a2e6074492d2fc21ad28a7b9d40457ac2a51ab7", size = 583230, upload-time = "2025-10-22T22:22:44.877Z" },
|
{ url = "https://files.pythonhosted.org/packages/f7/b3/1b1c9576839ff583d1428efbf59f9ee70498d8ce6c0b328ac02f1e470879/rpds_py-0.29.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:05a2bd42768ea988294ca328206efbcc66e220d2d9b7836ee5712c07ad6340ea", size = 600937, upload-time = "2025-11-16T14:48:56.247Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/66/df/62fc783781a121e77fee9a21ead0a926f1b652280a33f5956a5e7833ed30/rpds_py-0.28.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7a52a5169c664dfb495882adc75c304ae1d50df552fbd68e100fdc719dee4ff9", size = 553268, upload-time = "2025-10-22T22:22:46.441Z" },
|
{ url = "https://files.pythonhosted.org/packages/6c/7b/b6cfca2f9fee4c4494ce54f7fb1b9f578867495a9aa9fc0d44f5f735c8e0/rpds_py-0.29.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:33ca7bdfedd83339ca55da3a5e1527ee5870d4b8369456b5777b197756f3ca22", size = 564496, upload-time = "2025-11-16T14:48:57.691Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/84/85/d34366e335140a4837902d3dea89b51f087bd6a63c993ebdff59e93ee61d/rpds_py-0.28.0-cp313-cp313-win32.whl", hash = "sha256:2e42456917b6687215b3e606ab46aa6bca040c77af7df9a08a6dcfe8a4d10ca5", size = 217100, upload-time = "2025-10-22T22:22:48.342Z" },
|
{ url = "https://files.pythonhosted.org/packages/b9/fb/ba29ec7f0f06eb801bac5a23057a9ff7670623b5e8013bd59bec4aa09de8/rpds_py-0.29.0-cp313-cp313-win32.whl", hash = "sha256:20c51ae86a0bb9accc9ad4e6cdeec58d5ebb7f1b09dd4466331fc65e1766aae7", size = 223126, upload-time = "2025-11-16T14:48:59.058Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/3c/1c/f25a3f3752ad7601476e3eff395fe075e0f7813fbb9862bd67c82440e880/rpds_py-0.28.0-cp313-cp313-win_amd64.whl", hash = "sha256:e0a0311caedc8069d68fc2bf4c9019b58a2d5ce3cd7cb656c845f1615b577e1e", size = 227759, upload-time = "2025-10-22T22:22:50.219Z" },
|
{ url = "https://files.pythonhosted.org/packages/3c/6b/0229d3bed4ddaa409e6d90b0ae967ed4380e4bdd0dad6e59b92c17d42457/rpds_py-0.29.0-cp313-cp313-win_amd64.whl", hash = "sha256:6410e66f02803600edb0b1889541f4b5cc298a5ccda0ad789cc50ef23b54813e", size = 239771, upload-time = "2025-11-16T14:49:00.872Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e0/d6/5f39b42b99615b5bc2f36ab90423ea404830bdfee1c706820943e9a645eb/rpds_py-0.28.0-cp313-cp313-win_arm64.whl", hash = "sha256:04c1b207ab8b581108801528d59ad80aa83bb170b35b0ddffb29c20e411acdc1", size = 217326, upload-time = "2025-10-22T22:22:51.647Z" },
|
{ url = "https://files.pythonhosted.org/packages/e4/38/d2868f058b164f8efd89754d85d7b1c08b454f5c07ac2e6cc2e9bd4bd05b/rpds_py-0.29.0-cp313-cp313-win_arm64.whl", hash = "sha256:56838e1cd9174dc23c5691ee29f1d1be9eab357f27efef6bded1328b23e1ced2", size = 229994, upload-time = "2025-11-16T14:49:02.673Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/5c/8b/0c69b72d1cee20a63db534be0df271effe715ef6c744fdf1ff23bb2b0b1c/rpds_py-0.28.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:f296ea3054e11fc58ad42e850e8b75c62d9a93a9f981ad04b2e5ae7d2186ff9c", size = 355736, upload-time = "2025-10-22T22:22:53.211Z" },
|
{ url = "https://files.pythonhosted.org/packages/52/91/5de91c5ec7d41759beec9b251630824dbb8e32d20c3756da1a9a9d309709/rpds_py-0.29.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:37d94eadf764d16b9a04307f2ab1d7af6dc28774bbe0535c9323101e14877b4c", size = 365886, upload-time = "2025-11-16T14:49:04.133Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/f7/6d/0c2ee773cfb55c31a8514d2cece856dd299170a49babd50dcffb15ddc749/rpds_py-0.28.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5a7306c19b19005ad98468fcefeb7100b19c79fc23a5f24a12e06d91181193fa", size = 342677, upload-time = "2025-10-22T22:22:54.723Z" },
|
{ url = "https://files.pythonhosted.org/packages/85/7c/415d8c1b016d5f47ecec5145d9d6d21002d39dce8761b30f6c88810b455a/rpds_py-0.29.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d472cf73efe5726a067dce63eebe8215b14beabea7c12606fd9994267b3cfe2b", size = 355262, upload-time = "2025-11-16T14:49:05.543Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e2/1c/22513ab25a27ea205144414724743e305e8153e6abe81833b5e678650f5a/rpds_py-0.28.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5d9b86aa501fed9862a443c5c3116f6ead8bc9296185f369277c42542bd646b", size = 371847, upload-time = "2025-10-22T22:22:56.295Z" },
|
{ url = "https://files.pythonhosted.org/packages/3d/14/bf83e2daa4f980e4dc848aed9299792a8b84af95e12541d9e7562f84a6ef/rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:72fdfd5ff8992e4636621826371e3ac5f3e3b8323e9d0e48378e9c13c3dac9d0", size = 384826, upload-time = "2025-11-16T14:49:07.301Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/60/07/68e6ccdb4b05115ffe61d31afc94adef1833d3a72f76c9632d4d90d67954/rpds_py-0.28.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e5bbc701eff140ba0e872691d573b3d5d30059ea26e5785acba9132d10c8c31d", size = 381800, upload-time = "2025-10-22T22:22:57.808Z" },
|
{ url = "https://files.pythonhosted.org/packages/33/b8/53330c50a810ae22b4fbba5e6cf961b68b9d72d9bd6780a7c0a79b070857/rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2549d833abdf8275c901313b9e8ff8fba57e50f6a495035a2a4e30621a2f7cc4", size = 394234, upload-time = "2025-11-16T14:49:08.782Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/73/bf/6d6d15df80781d7f9f368e7c1a00caf764436518c4877fb28b029c4624af/rpds_py-0.28.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a5690671cd672a45aa8616d7374fdf334a1b9c04a0cac3c854b1136e92374fe", size = 518827, upload-time = "2025-10-22T22:22:59.826Z" },
|
{ url = "https://files.pythonhosted.org/packages/cc/32/01e2e9645cef0e584f518cfde4567563e57db2257244632b603f61b40e50/rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4448dad428f28a6a767c3e3b80cde3446a22a0efbddaa2360f4bb4dc836d0688", size = 520008, upload-time = "2025-11-16T14:49:10.253Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/7b/d3/2decbb2976cc452cbf12a2b0aaac5f1b9dc5dd9d1f7e2509a3ee00421249/rpds_py-0.28.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9f1d92ecea4fa12f978a367c32a5375a1982834649cdb96539dcdc12e609ab1a", size = 399471, upload-time = "2025-10-22T22:23:01.968Z" },
|
{ url = "https://files.pythonhosted.org/packages/98/c3/0d1b95a81affae2b10f950782e33a1fd2edd6ce2a479966cac98c9a66f57/rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:115f48170fd4296a33938d8c11f697f5f26e0472e43d28f35624764173a60e4d", size = 409569, upload-time = "2025-11-16T14:49:12.478Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b1/2c/f30892f9e54bd02e5faca3f6a26d6933c51055e67d54818af90abed9748e/rpds_py-0.28.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d252db6b1a78d0a3928b6190156042d54c93660ce4d98290d7b16b5296fb7cc", size = 377578, upload-time = "2025-10-22T22:23:03.52Z" },
|
{ url = "https://files.pythonhosted.org/packages/fa/60/aa3b8678f3f009f675b99174fa2754302a7fbfe749162e8043d111de2d88/rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e5bb73ffc029820f4348e9b66b3027493ae00bca6629129cd433fd7a76308ee", size = 385188, upload-time = "2025-11-16T14:49:13.88Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/f0/5d/3bce97e5534157318f29ac06bf2d279dae2674ec12f7cb9c12739cee64d8/rpds_py-0.28.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:d61b355c3275acb825f8777d6c4505f42b5007e357af500939d4a35b19177259", size = 390482, upload-time = "2025-10-22T22:23:05.391Z" },
|
{ url = "https://files.pythonhosted.org/packages/92/02/5546c1c8aa89c18d40c1fcffdcc957ba730dee53fb7c3ca3a46f114761d2/rpds_py-0.29.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:b1581fcde18fcdf42ea2403a16a6b646f8eb1e58d7f90a0ce693da441f76942e", size = 398587, upload-time = "2025-11-16T14:49:15.339Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e3/f0/886bd515ed457b5bd93b166175edb80a0b21a210c10e993392127f1e3931/rpds_py-0.28.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:acbe5e8b1026c0c580d0321c8aae4b0a1e1676861d48d6e8c6586625055b606a", size = 402447, upload-time = "2025-10-22T22:23:06.93Z" },
|
{ url = "https://files.pythonhosted.org/packages/6c/e0/ad6eeaf47e236eba052fa34c4073078b9e092bd44da6bbb35aaae9580669/rpds_py-0.29.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16e9da2bda9eb17ea318b4c335ec9ac1818e88922cbe03a5743ea0da9ecf74fb", size = 416641, upload-time = "2025-11-16T14:49:16.832Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/42/b5/71e8777ac55e6af1f4f1c05b47542a1eaa6c33c1cf0d300dca6a1c6e159a/rpds_py-0.28.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:8aa23b6f0fc59b85b4c7d89ba2965af274346f738e8d9fc2455763602e62fd5f", size = 552385, upload-time = "2025-10-22T22:23:08.557Z" },
|
{ url = "https://files.pythonhosted.org/packages/1a/93/0acedfd50ad9cdd3879c615a6dc8c5f1ce78d2fdf8b87727468bb5bb4077/rpds_py-0.29.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:28fd300326dd21198f311534bdb6d7e989dd09b3418b3a91d54a0f384c700967", size = 566683, upload-time = "2025-11-16T14:49:18.342Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/5d/cb/6ca2d70cbda5a8e36605e7788c4aa3bea7c17d71d213465a5a675079b98d/rpds_py-0.28.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7b14b0c680286958817c22d76fcbca4800ddacef6f678f3a7c79a1fe7067fe37", size = 575642, upload-time = "2025-10-22T22:23:10.348Z" },
|
{ url = "https://files.pythonhosted.org/packages/62/53/8c64e0f340a9e801459fc6456821abc15b3582cb5dc3932d48705a9d9ac7/rpds_py-0.29.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2aba991e041d031c7939e1358f583ae405a7bf04804ca806b97a5c0e0af1ea5e", size = 592730, upload-time = "2025-11-16T14:49:19.767Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4a/d4/407ad9960ca7856d7b25c96dcbe019270b5ffdd83a561787bc682c797086/rpds_py-0.28.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:bcf1d210dfee61a6c86551d67ee1031899c0fdbae88b2d44a569995d43797712", size = 544507, upload-time = "2025-10-22T22:23:12.434Z" },
|
{ url = "https://files.pythonhosted.org/packages/85/ef/3109b6584f8c4b0d2490747c916df833c127ecfa82be04d9a40a376f2090/rpds_py-0.29.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:7f437026dbbc3f08c99cc41a5b2570c6e1a1ddbe48ab19a9b814254128d4ea7a", size = 557361, upload-time = "2025-11-16T14:49:21.574Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/51/31/2f46fe0efcac23fbf5797c6b6b7e1c76f7d60773e525cb65fcbc582ee0f2/rpds_py-0.28.0-cp313-cp313t-win32.whl", hash = "sha256:3aa4dc0fdab4a7029ac63959a3ccf4ed605fee048ba67ce89ca3168da34a1342", size = 205376, upload-time = "2025-10-22T22:23:13.979Z" },
|
{ url = "https://files.pythonhosted.org/packages/ff/3b/61586475e82d57f01da2c16edb9115a618afe00ce86fe1b58936880b15af/rpds_py-0.29.0-cp313-cp313t-win32.whl", hash = "sha256:6e97846e9800a5d0fe7be4d008f0c93d0feeb2700da7b1f7528dabafb31dfadb", size = 211227, upload-time = "2025-11-16T14:49:23.03Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/92/e4/15947bda33cbedfc134490a41841ab8870a72a867a03d4969d886f6594a2/rpds_py-0.28.0-cp313-cp313t-win_amd64.whl", hash = "sha256:7b7d9d83c942855e4fdcfa75d4f96f6b9e272d42fffcb72cd4bb2577db2e2907", size = 215907, upload-time = "2025-10-22T22:23:15.5Z" },
|
{ url = "https://files.pythonhosted.org/packages/3b/3a/12dc43f13594a54ea0c9d7e9d43002116557330e3ad45bc56097ddf266e2/rpds_py-0.29.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f49196aec7c4b406495f60e6f947ad71f317a765f956d74bbd83996b9edc0352", size = 225248, upload-time = "2025-11-16T14:49:24.841Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue