Merge "Ubuntu: define implied VLAN parent interfaces in networkd"
This commit is contained in:
commit
c98cd6c520
@ -284,7 +284,6 @@ def _network(context, name, inventory_hostname, bridge, bond, vlan_interfaces):
|
|||||||
{
|
{
|
||||||
'Network': [
|
'Network': [
|
||||||
{'Address': ip},
|
{'Address': ip},
|
||||||
{'Broadcast': 'true' if ip else None},
|
|
||||||
{'Gateway': gateway},
|
{'Gateway': gateway},
|
||||||
{'DHCP': ('yes' if bootproto and bootproto.lower() == 'dhcp'
|
{'DHCP': ('yes' if bootproto and bootproto.lower() == 'dhcp'
|
||||||
else None)},
|
else None)},
|
||||||
@ -317,6 +316,34 @@ def _network(context, name, inventory_hostname, bridge, bond, vlan_interfaces):
|
|||||||
return _filter_options(config)
|
return _filter_options(config)
|
||||||
|
|
||||||
|
|
||||||
|
def _vlan_parent_network(device, mtu, vlan_interfaces):
|
||||||
|
"""Return a networkd network configuration for a VLAN parent interface.
|
||||||
|
|
||||||
|
:param device: name of the interface.
|
||||||
|
:param mtu: Interface MTU.
|
||||||
|
:param vlan_interfaces: List of VLAN subinterfaces of the interface.
|
||||||
|
"""
|
||||||
|
config = [
|
||||||
|
{
|
||||||
|
'Match': [
|
||||||
|
{'Name': device},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'Network': [
|
||||||
|
{'VLAN': vlan_interface}
|
||||||
|
for vlan_interface in vlan_interfaces
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'Link': [
|
||||||
|
{'MTUBytes': mtu},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
return _filter_options(config)
|
||||||
|
|
||||||
|
|
||||||
def _bridge_port_network(context, name, port, inventory_hostname,
|
def _bridge_port_network(context, name, port, inventory_hostname,
|
||||||
vlan_interfaces):
|
vlan_interfaces):
|
||||||
"""Return a networkd network configuration for a bridge port.
|
"""Return a networkd network configuration for a bridge port.
|
||||||
@ -437,6 +464,25 @@ def _veth_peer_network(context, veth, inventory_hostname):
|
|||||||
return _filter_options(config)
|
return _filter_options(config)
|
||||||
|
|
||||||
|
|
||||||
|
def _add_to_result(result, prefix, device, config):
|
||||||
|
"""Add configuration for an interface to a filter result.
|
||||||
|
|
||||||
|
:param result: the result dict.
|
||||||
|
:param prefix: the systemd-networkd configuration file prefix.
|
||||||
|
:param device: the interface being configured.
|
||||||
|
:param config: the configuration to add to the result.
|
||||||
|
:raises: AnsibleFilterError if the interface already exists in the result.
|
||||||
|
"""
|
||||||
|
key = "%s%s" % (prefix, device)
|
||||||
|
# Catch the case where interface configuration is added multiple times.
|
||||||
|
# This should not happen.
|
||||||
|
if key in result:
|
||||||
|
raise errors.AnsibleFilterError(
|
||||||
|
"Programming error: duplicate interface configuration for %s"
|
||||||
|
% device)
|
||||||
|
result[key] = config
|
||||||
|
|
||||||
|
|
||||||
@jinja2.contextfilter
|
@jinja2.contextfilter
|
||||||
def networkd_netdevs(context, names, inventory_hostname=None):
|
def networkd_netdevs(context, names, inventory_hostname=None):
|
||||||
"""Return a dict representation of networkd NetDev configuration.
|
"""Return a dict representation of networkd NetDev configuration.
|
||||||
@ -459,7 +505,7 @@ def networkd_netdevs(context, names, inventory_hostname=None):
|
|||||||
device = networks.get_and_validate_interface(context, name,
|
device = networks.get_and_validate_interface(context, name,
|
||||||
inventory_hostname)
|
inventory_hostname)
|
||||||
netdev = _vlan_netdev(context, name, inventory_hostname)
|
netdev = _vlan_netdev(context, name, inventory_hostname)
|
||||||
result["%s%s" % (prefix, device)] = netdev
|
_add_to_result(result, prefix, device, netdev)
|
||||||
|
|
||||||
# Bridges.
|
# Bridges.
|
||||||
for name in networks.net_select_bridges(context, names,
|
for name in networks.net_select_bridges(context, names,
|
||||||
@ -467,21 +513,21 @@ def networkd_netdevs(context, names, inventory_hostname=None):
|
|||||||
device = networks.get_and_validate_interface(context, name,
|
device = networks.get_and_validate_interface(context, name,
|
||||||
inventory_hostname)
|
inventory_hostname)
|
||||||
netdev = _bridge_netdev(context, name, inventory_hostname)
|
netdev = _bridge_netdev(context, name, inventory_hostname)
|
||||||
result["%s%s" % (prefix, device)] = netdev
|
_add_to_result(result, prefix, device, netdev)
|
||||||
|
|
||||||
# Bonds.
|
# Bonds.
|
||||||
for name in networks.net_select_bonds(context, names, inventory_hostname):
|
for name in networks.net_select_bonds(context, names, inventory_hostname):
|
||||||
device = networks.get_and_validate_interface(context, name,
|
device = networks.get_and_validate_interface(context, name,
|
||||||
inventory_hostname)
|
inventory_hostname)
|
||||||
netdev = _bond_netdev(context, name, inventory_hostname)
|
netdev = _bond_netdev(context, name, inventory_hostname)
|
||||||
result["%s%s" % (prefix, device)] = netdev
|
_add_to_result(result, prefix, device, netdev)
|
||||||
|
|
||||||
# Virtual Ethernet pairs.
|
# Virtual Ethernet pairs.
|
||||||
veths = networks.get_ovs_veths(context, names, inventory_hostname)
|
veths = networks.get_ovs_veths(context, names, inventory_hostname)
|
||||||
for veth in veths:
|
for veth in veths:
|
||||||
netdev = _veth_netdev(context, veth, inventory_hostname)
|
netdev = _veth_netdev(context, veth, inventory_hostname)
|
||||||
device = veth['name']
|
device = veth['name']
|
||||||
result["%s%s" % (prefix, device)] = netdev
|
_add_to_result(result, prefix, device, netdev)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@ -551,9 +597,10 @@ def networkd_networks(context, names, inventory_hostname=None):
|
|||||||
device = networks.get_and_validate_interface(context, name,
|
device = networks.get_and_validate_interface(context, name,
|
||||||
inventory_hostname)
|
inventory_hostname)
|
||||||
vlan = networks.net_vlan(context, name, inventory_hostname)
|
vlan = networks.net_vlan(context, name, inventory_hostname)
|
||||||
|
mtu = networks.net_mtu(context, name, inventory_hostname)
|
||||||
parent = networks.get_vlan_parent(device, vlan)
|
parent = networks.get_vlan_parent(device, vlan)
|
||||||
vlan_interfaces = interface_to_vlans.setdefault(parent, [])
|
vlan_interfaces = interface_to_vlans.setdefault(parent, [])
|
||||||
vlan_interfaces.append(device)
|
vlan_interfaces.append({"device": device, "mtu": mtu})
|
||||||
|
|
||||||
# Prefix for configuration file names.
|
# Prefix for configuration file names.
|
||||||
prefix = utils.get_hostvar(context, "networkd_prefix", inventory_hostname)
|
prefix = utils.get_hostvar(context, "networkd_prefix", inventory_hostname)
|
||||||
@ -568,8 +615,22 @@ def networkd_networks(context, names, inventory_hostname=None):
|
|||||||
bond = bond_member_to_bond.get(device)
|
bond = bond_member_to_bond.get(device)
|
||||||
vlan_interfaces = interface_to_vlans.get(device, [])
|
vlan_interfaces = interface_to_vlans.get(device, [])
|
||||||
net = _network(context, name, inventory_hostname, bridge, bond,
|
net = _network(context, name, inventory_hostname, bridge, bond,
|
||||||
vlan_interfaces)
|
[vlan["device"] for vlan in vlan_interfaces])
|
||||||
result["%s%s" % (prefix, device)] = net
|
_add_to_result(result, prefix, device, net)
|
||||||
|
|
||||||
|
# VLAN parent interfaces that are not in configured networks, bridge ports
|
||||||
|
# or bond members.
|
||||||
|
implied_vlan_parents = (set(interface_to_vlans) -
|
||||||
|
set(interfaces) -
|
||||||
|
set(bridge_port_to_bridge) -
|
||||||
|
set(bond_member_to_bond))
|
||||||
|
for device in implied_vlan_parents:
|
||||||
|
vlan_interfaces = interface_to_vlans[device]
|
||||||
|
mtu = max([vlan["mtu"] for vlan in vlan_interfaces])
|
||||||
|
net = _vlan_parent_network(device, mtu,
|
||||||
|
[vlan["device"]
|
||||||
|
for vlan in vlan_interfaces])
|
||||||
|
_add_to_result(result, prefix, device, net)
|
||||||
|
|
||||||
# Bridge ports that are not in configured networks.
|
# Bridge ports that are not in configured networks.
|
||||||
for name in networks.net_select_bridges(context, names,
|
for name in networks.net_select_bridges(context, names,
|
||||||
@ -580,9 +641,10 @@ def networkd_networks(context, names, inventory_hostname=None):
|
|||||||
inventory_hostname)
|
inventory_hostname)
|
||||||
for port in set(bridge_ports) - set(interfaces):
|
for port in set(bridge_ports) - set(interfaces):
|
||||||
vlan_interfaces = interface_to_vlans.get(port, [])
|
vlan_interfaces = interface_to_vlans.get(port, [])
|
||||||
netdev = _bridge_port_network(context, name, port,
|
net = _bridge_port_network(context, name, port, inventory_hostname,
|
||||||
inventory_hostname, vlan_interfaces)
|
[vlan["device"]
|
||||||
result["%s%s" % (prefix, port)] = netdev
|
for vlan in vlan_interfaces])
|
||||||
|
_add_to_result(result, prefix, port, net)
|
||||||
|
|
||||||
# Bond members that are not in configured networks.
|
# Bond members that are not in configured networks.
|
||||||
for name in networks.net_select_bonds(context, names, inventory_hostname):
|
for name in networks.net_select_bonds(context, names, inventory_hostname):
|
||||||
@ -592,20 +654,22 @@ def networkd_networks(context, names, inventory_hostname=None):
|
|||||||
inventory_hostname)
|
inventory_hostname)
|
||||||
for member in set(bond_members) - set(interfaces):
|
for member in set(bond_members) - set(interfaces):
|
||||||
vlan_interfaces = interface_to_vlans.get(member, [])
|
vlan_interfaces = interface_to_vlans.get(member, [])
|
||||||
netdev = _bond_member_network(context, name, member,
|
net = _bond_member_network(context, name, member,
|
||||||
inventory_hostname, vlan_interfaces)
|
inventory_hostname,
|
||||||
result["%s%s" % (prefix, member)] = netdev
|
[vlan["device"]
|
||||||
|
for vlan in vlan_interfaces])
|
||||||
|
_add_to_result(result, prefix, member, net)
|
||||||
|
|
||||||
# Virtual Ethernet pairs for Open vSwitch.
|
# Virtual Ethernet pairs for Open vSwitch.
|
||||||
veths = networks.get_ovs_veths(context, names, inventory_hostname)
|
veths = networks.get_ovs_veths(context, names, inventory_hostname)
|
||||||
for veth in veths:
|
for veth in veths:
|
||||||
net = _veth_network(context, veth, inventory_hostname)
|
net = _veth_network(context, veth, inventory_hostname)
|
||||||
device = veth['name']
|
device = veth['name']
|
||||||
result["%s%s" % (prefix, device)] = net
|
_add_to_result(result, prefix, device, net)
|
||||||
|
|
||||||
net = _veth_peer_network(context, veth, inventory_hostname)
|
net = _veth_peer_network(context, veth, inventory_hostname)
|
||||||
device = veth['peer']
|
device = veth['peer']
|
||||||
result["%s%s" % (prefix, device)] = net
|
_add_to_result(result, prefix, device, net)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -298,7 +298,6 @@ class TestNetworkdNetworks(BaseNetworkdTest):
|
|||||||
{
|
{
|
||||||
"Network": [
|
"Network": [
|
||||||
{"Address": "1.2.3.4/24"},
|
{"Address": "1.2.3.4/24"},
|
||||||
{"Broadcast": "true"},
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@ -347,7 +346,6 @@ class TestNetworkdNetworks(BaseNetworkdTest):
|
|||||||
{
|
{
|
||||||
"Network": [
|
"Network": [
|
||||||
{"Address": "1.2.3.4/24"},
|
{"Address": "1.2.3.4/24"},
|
||||||
{"Broadcast": "true"},
|
|
||||||
{"Gateway": "1.2.3.1"},
|
{"Gateway": "1.2.3.1"},
|
||||||
{"DHCP": "yes"},
|
{"DHCP": "yes"},
|
||||||
{'UseGateway': "false"},
|
{'UseGateway': "false"},
|
||||||
@ -400,6 +398,18 @@ class TestNetworkdNetworks(BaseNetworkdTest):
|
|||||||
def test_vlan(self):
|
def test_vlan(self):
|
||||||
nets = networkd.networkd_networks(self.context, ["net2"])
|
nets = networkd.networkd_networks(self.context, ["net2"])
|
||||||
expected = {
|
expected = {
|
||||||
|
"50-kayobe-eth0": [
|
||||||
|
{
|
||||||
|
"Match": [
|
||||||
|
{"Name": "eth0"}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Network": [
|
||||||
|
{"VLAN": "eth0.2"},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
"50-kayobe-eth0.2": [
|
"50-kayobe-eth0.2": [
|
||||||
{
|
{
|
||||||
"Match": [
|
"Match": [
|
||||||
@ -422,7 +432,6 @@ class TestNetworkdNetworks(BaseNetworkdTest):
|
|||||||
{
|
{
|
||||||
"Network": [
|
"Network": [
|
||||||
{"Address": "1.2.3.4/24"},
|
{"Address": "1.2.3.4/24"},
|
||||||
{"Broadcast": "true"},
|
|
||||||
{"VLAN": "eth0.2"},
|
{"VLAN": "eth0.2"},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -527,6 +536,106 @@ class TestNetworkdNetworks(BaseNetworkdTest):
|
|||||||
}
|
}
|
||||||
self.assertEqual(expected, nets)
|
self.assertEqual(expected, nets)
|
||||||
|
|
||||||
|
def test_bridge_with_bridge_port_vlan(self):
|
||||||
|
# Test the case where one of the bridge ports has a VLAN subinterface.
|
||||||
|
self._update_context({
|
||||||
|
"net2_interface": "eth1.2",
|
||||||
|
})
|
||||||
|
nets = networkd.networkd_networks(self.context, ["net2", "net3"])
|
||||||
|
expected = {
|
||||||
|
"50-kayobe-br0": [
|
||||||
|
{
|
||||||
|
"Match": [
|
||||||
|
{"Name": "br0"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"50-kayobe-eth0": [
|
||||||
|
{
|
||||||
|
"Match": [
|
||||||
|
{"Name": "eth0"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Network": [
|
||||||
|
{"Bridge": "br0"},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"50-kayobe-eth1": [
|
||||||
|
{
|
||||||
|
"Match": [
|
||||||
|
{"Name": "eth1"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Network": [
|
||||||
|
{"Bridge": "br0"},
|
||||||
|
{"VLAN": "eth1.2"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"50-kayobe-eth1.2": [
|
||||||
|
{
|
||||||
|
"Match": [
|
||||||
|
{"Name": "eth1.2"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
self.assertEqual(expected, nets)
|
||||||
|
|
||||||
|
def test_bridge_with_bridge_port_vlan_net(self):
|
||||||
|
# Test the case where one of the bridge ports has a VLAN subinterface,
|
||||||
|
# and is also a Kayobe network (here eth0 is net1).
|
||||||
|
self._update_context({
|
||||||
|
"net1_ips": None,
|
||||||
|
})
|
||||||
|
nets = networkd.networkd_networks(self.context,
|
||||||
|
["net1", "net2", "net3"])
|
||||||
|
expected = {
|
||||||
|
"50-kayobe-br0": [
|
||||||
|
{
|
||||||
|
"Match": [
|
||||||
|
{"Name": "br0"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"50-kayobe-eth0": [
|
||||||
|
{
|
||||||
|
"Match": [
|
||||||
|
{"Name": "eth0"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Network": [
|
||||||
|
{"Bridge": "br0"},
|
||||||
|
{"VLAN": "eth0.2"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"50-kayobe-eth0.2": [
|
||||||
|
{
|
||||||
|
"Match": [
|
||||||
|
{"Name": "eth0.2"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"50-kayobe-eth1": [
|
||||||
|
{
|
||||||
|
"Match": [
|
||||||
|
{"Name": "eth1"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Network": [
|
||||||
|
{"Bridge": "br0"},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
self.assertEqual(expected, nets)
|
||||||
|
|
||||||
def test_bridge_no_interface(self):
|
def test_bridge_no_interface(self):
|
||||||
self._update_context({"net3_interface": None})
|
self._update_context({"net3_interface": None})
|
||||||
self.assertRaises(errors.AnsibleFilterError,
|
self.assertRaises(errors.AnsibleFilterError,
|
||||||
@ -617,6 +726,106 @@ class TestNetworkdNetworks(BaseNetworkdTest):
|
|||||||
}
|
}
|
||||||
self.assertEqual(expected, nets)
|
self.assertEqual(expected, nets)
|
||||||
|
|
||||||
|
def test_bond_with_bond_member_vlan(self):
|
||||||
|
# Test the case where one of the bond members has a VLAN subinterface.
|
||||||
|
self._update_context({
|
||||||
|
"net2_interface": "eth1.2",
|
||||||
|
})
|
||||||
|
nets = networkd.networkd_networks(self.context, ["net2", "net4"])
|
||||||
|
expected = {
|
||||||
|
"50-kayobe-bond0": [
|
||||||
|
{
|
||||||
|
"Match": [
|
||||||
|
{"Name": "bond0"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"50-kayobe-eth0": [
|
||||||
|
{
|
||||||
|
"Match": [
|
||||||
|
{"Name": "eth0"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Network": [
|
||||||
|
{"Bond": "bond0"},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"50-kayobe-eth1": [
|
||||||
|
{
|
||||||
|
"Match": [
|
||||||
|
{"Name": "eth1"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Network": [
|
||||||
|
{"Bond": "bond0"},
|
||||||
|
{"VLAN": "eth1.2"},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"50-kayobe-eth1.2": [
|
||||||
|
{
|
||||||
|
"Match": [
|
||||||
|
{"Name": "eth1.2"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
self.assertEqual(expected, nets)
|
||||||
|
|
||||||
|
def test_bond_with_bond_member_vlan_net(self):
|
||||||
|
# Test the case where one of the bond members has a VLAN subinterface,
|
||||||
|
# and is also a Kayobe network (here eth0 is net1).
|
||||||
|
self._update_context({
|
||||||
|
"net1_ips": None,
|
||||||
|
})
|
||||||
|
nets = networkd.networkd_networks(self.context,
|
||||||
|
["net1", "net2", "net4"])
|
||||||
|
expected = {
|
||||||
|
"50-kayobe-bond0": [
|
||||||
|
{
|
||||||
|
"Match": [
|
||||||
|
{"Name": "bond0"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"50-kayobe-eth0": [
|
||||||
|
{
|
||||||
|
"Match": [
|
||||||
|
{"Name": "eth0"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Network": [
|
||||||
|
{"Bond": "bond0"},
|
||||||
|
{"VLAN": "eth0.2"},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"50-kayobe-eth0.2": [
|
||||||
|
{
|
||||||
|
"Match": [
|
||||||
|
{"Name": "eth0.2"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"50-kayobe-eth1": [
|
||||||
|
{
|
||||||
|
"Match": [
|
||||||
|
{"Name": "eth1"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Network": [
|
||||||
|
{"Bond": "bond0"},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
self.assertEqual(expected, nets)
|
||||||
|
|
||||||
def test_bond_no_interface(self):
|
def test_bond_no_interface(self):
|
||||||
self._update_context({"net4_interface": None})
|
self._update_context({"net4_interface": None})
|
||||||
self.assertRaises(errors.AnsibleFilterError,
|
self.assertRaises(errors.AnsibleFilterError,
|
||||||
@ -737,7 +946,6 @@ class TestNetworkdNetworks(BaseNetworkdTest):
|
|||||||
{
|
{
|
||||||
"Network": [
|
"Network": [
|
||||||
{"Address": "1.2.3.4/24"},
|
{"Address": "1.2.3.4/24"},
|
||||||
{"Broadcast": "true"},
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@ -760,7 +968,6 @@ class TestNetworkdNetworks(BaseNetworkdTest):
|
|||||||
{
|
{
|
||||||
"Network": [
|
"Network": [
|
||||||
{"Address": "1.2.3.4/24"},
|
{"Address": "1.2.3.4/24"},
|
||||||
{"Broadcast": "true"},
|
|
||||||
{"VLAN": "eth0.2"},
|
{"VLAN": "eth0.2"},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
3
tox.ini
3
tox.ini
@ -135,8 +135,9 @@ commands =
|
|||||||
|
|
||||||
[flake8]
|
[flake8]
|
||||||
# E123, E125 skipped as they are invalid PEP-8.
|
# E123, E125 skipped as they are invalid PEP-8.
|
||||||
|
# W504 line break after binary operator
|
||||||
|
|
||||||
show-source = True
|
show-source = True
|
||||||
ignore = E123,E125
|
ignore = E123,E125,W504
|
||||||
builtins = _
|
builtins = _
|
||||||
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build
|
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build
|
||||||
|
Loading…
Reference in New Issue
Block a user