#!/usr/bin/env perl
# pyimportcan.pl -- Python imports canonical format filter
# Copyright (C) 2013-2018 Sergey Matveev (stargrave@stargrave.org)
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
=pod
=head1 PROBLEM
Python allows various different formats of how to make importing of
modules and functions:
from foo import bar
from foo import bar, baz
from foo import (
bar,
baz
)
from foo import (
baz,
bar,
)
from foo import bar, \
baz
Everything can be unsorted at any place, thus making the task of
checking if import already exists rather hard. Moreover it complicates
just adding another import, because you have to find it first and deal
with the format it is already written.
Everything can use different indentation practices. Everything can be
doubled and you won't notice it:
from foo import bar
[many lines]
from foo import (
baz,
bar
)
Allowing multiple imports on one line leads to possibility of long lines
appearing.
The whole import sections with various formats just can not be
technically sorted with the editor (no way to do "vip:sort" in Vim).
Merge conflict in the imports section can be not so trivial to resolve,
however in most cases just aggregating them will be enough.
If you want to find the code that imports bar from foo, then you can do
it with "from foo import bar", but can not with "import (\n" is most
cases. You are forced to use special Python-related software to deal
with it, but no grep or sed.
=head1 SOLUTION
Use the very convenient simple single format. Single import per line,
period. Sorted and only identical ones. With git merge conflict lines
removed. This script reads stdin with import-lines and writes canonical
representation of them to stdout. For example you can select lines in
Vim and just enter ":!pyimportcan.pl".
From that kind of imports:
from waaccounts.models import OrgRole
import math
from waaccounts.models import UserAccount
from waadv.filters import AdvCampaignFilterSet as foo1
from waadv.filters import AdvCampaignBidFilterSet
from waadv.filters import AdvCampaignUniqueShowFilterSet as foo2
from waadv.filters import VasttaskFilterSet
from waadv.forms import AdvCampaignCreateForm
from waadv.forms import PriceListTotalBudgetDiscountFormset
from waadv.models import Adv
from waadv.models import PriceListTotalBudgetDiscount
from waadv.models import VastTask
from wacontent.models import VrContractGroup
from wacatalog.models import AdvGroup
from wahelpers.counters import adv_campaign_click_counter_loader
from wahelpers.counters import adv_video_view_fact_counter_loader
from wahelpers.counters import adv_view_percent
from wahelpers.counters import ctr
from wahelpers.functions import get_json_rpc_proxy, get_return_url
<<<<<<< HEAD
from waorigin.kendo_menus.toolbar import KendoGridToolbar
from waorigin.kendo_menus.toolbar_button import KendoToolbarButton
=======
from http_utils import JSONResponse
from wahelpers.counters import (
adv_campaign_click_counter_loader,
adv_campaign_click_fact_counter_loader,
ctr,
adv_view_percent,
)
from waorigin.kendo_menus.toolbar_button import (
AddKendoToolbarButton,
StatusKendoToolbarButton
)
from waorigin.models import Content, ContentCategory3 as foo4, ContentCategory2, Files
from waorigin.views import filter_view, model_autocompletion, \
create_update_with_auto_user, get_objects_for_edit_many
from wapartners.models import PrNomenclature, PrSite
>>>>>>> 1bf0b64... fixed view refs #11992
from waorigin.kendo_data_source import KendoDataSourceView
from waorigin.models import Content
from waorigin.models import ContentCategory2
from waorigin.models import ContentCategory3
from waorigin.models import Files
from waorigin.views import create_update_with_auto_user
from waorigin.views import filter_view
from waorigin.views import get_objects_for_edit_many
from waorigin.views import model_autocompletion
from wapartners.models import PrSite
from wapartners.models import PrNomenclature
it makes the following one (by feeding it to stdin and capturing on
stdout):
import math
from http_utils import JSONResponse
from waaccounts.models import OrgRole
from waaccounts.models import UserAccount
from waadv.filters import AdvCampaignBidFilterSet
from waadv.filters import AdvCampaignFilterSet as foo1
from waadv.filters import AdvCampaignUniqueShowFilterSet as foo2
from waadv.filters import VasttaskFilterSet
from waadv.forms import AdvCampaignCreateForm
from waadv.forms import PriceListTotalBudgetDiscountFormset
from waadv.models import Adv
from waadv.models import PriceListTotalBudgetDiscount
from waadv.models import VastTask
from wacatalog.models import AdvGroup
from wacontent.models import VrContractGroup
from wahelpers.counters import adv_campaign_click_counter_loader
from wahelpers.counters import adv_campaign_click_fact_counter_loader
from wahelpers.counters import adv_video_view_fact_counter_loader
from wahelpers.counters import adv_view_percent
from wahelpers.counters import ctr
from wahelpers.functions import get_json_rpc_proxy
from wahelpers.functions import get_return_url
from waorigin.kendo_data_source import KendoDataSourceView
from waorigin.kendo_menus.toolbar import KendoGridToolbar
from waorigin.kendo_menus.toolbar_button import AddKendoToolbarButton
from waorigin.kendo_menus.toolbar_button import KendoToolbarButton
from waorigin.kendo_menus.toolbar_button import StatusKendoToolbarButton
from waorigin.models import Content
from waorigin.models import ContentCategory2
from waorigin.models import ContentCategory3
from waorigin.models import ContentCategory3 as foo4
from waorigin.models import Files
from waorigin.views import create_update_with_auto_user
from waorigin.views import filter_view
from waorigin.views import get_objects_for_edit_many
from waorigin.views import model_autocompletion
from wapartners.models import PrNomenclature
from wapartners.models import PrSite
=head1 AUTHOR
Sergey Matveev L
=cut
use strict;
use warnings;
my $buf;
my $con;
my @imports;
my %parsed;
# Collect strings and aggregate the splitted ones
while(<>){
next if /^[<=>]{2,}/;
next if /^\s*#/;
chop;
$buf = ($con ? $buf : "") . $_;
$con = /[\\,\(]\s*$/ ? 1 : 0;
next if /^\s*\)*\s*$/;
push @imports, $buf;
};
# Consolidate information from where what is imported
foreach (@imports) {
s/[\\\(\)]//g;
s/ */ /g;
next if /import\s*$/;
/^(.*)\s*import\s*(.*)$/;
my ($where, $what) = ($1, $2);
map { $parsed{$where}->{$_}++ } split /\s*,\s*/, $what;
};
foreach my $where (sort keys %parsed){
map { print $where . "import $_\n" } sort keys %{$parsed{$where}};
};