making a LOT of headway on the gi stuff but hitting a namespace issue
This commit is contained in:
parent
0ad8314d0b
commit
27978786b8
@ -1,13 +1,20 @@
|
|||||||
|
try:
|
||||||
|
from . import constants
|
||||||
|
except ImportError:
|
||||||
|
from . import constants_fallback as constants
|
||||||
|
|
||||||
from . import disk
|
from . import disk
|
||||||
from . import system
|
from . import system
|
||||||
from . import config
|
from . import config
|
||||||
from . import constants
|
|
||||||
from . import envsetup
|
from . import envsetup
|
||||||
from . import log
|
from . import log
|
||||||
from . import network
|
from . import network
|
||||||
from . import pacman
|
from . import pacman
|
||||||
from . import utils
|
from . import utils
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class AIF(object):
|
class AIF(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
@ -1,13 +1,22 @@
|
|||||||
arch_releng_key = '4AA4767BBC9C4B1D18AE28B77F2D434B9741E8AC'
|
from .constants_fallback import *
|
||||||
version = '0.2.0'
|
##
|
||||||
external_deps = ['blkinfo',
|
import aif.disk._common
|
||||||
'gpg',
|
_BlockDev = aif.disk._common.BlockDev
|
||||||
'lxml',
|
aif.disk._common.addBDPlugin('part')
|
||||||
'mdstat',
|
|
||||||
'passlib',
|
|
||||||
'psutil',
|
# LIBBLOCKDEV FLAG INDEXING / PARTED <=> LIBBLOCKDEV FLAG CONVERSION
|
||||||
'pyparted',
|
BD_PART_FLAGS = _BlockDev.PartFlag(-1)
|
||||||
'pyroute2',
|
BD_PART_FLAGS_FRIENDLY = dict(zip(BD_PART_FLAGS.value_nicks, BD_PART_FLAGS.value_names))
|
||||||
'pytz',
|
BD_PARTED_MAP = {'apple_tv_recovery': 'atvrecv',
|
||||||
'requests',
|
'cpalo': 'palo',
|
||||||
'validators']
|
'gpt_hidden': None, # ???
|
||||||
|
'gpt_no_automount': None, # ???
|
||||||
|
'gpt_read_only': None, # ???
|
||||||
|
'gpt_system_part': None, # ???
|
||||||
|
'hpservice': 'hp-service',
|
||||||
|
'msft_data': 'msftdata',
|
||||||
|
'msft_reserved': 'msftres'}
|
||||||
|
PARTED_BD_MAP = {v: k for k, v in BD_PARTED_MAP.items() if v is not None}
|
||||||
|
BD_PART_FLAGS_IDX_FLAG = {k: v.value_nicks[0] for k, v in BD_PART_FLAGS.__flags_values__.items()}
|
||||||
|
BD_PART_FLAGS_FLAG_IDX = {v: k for k, v in BD_PART_FLAGS_IDX_FLAG.items()}
|
||||||
|
21
aif/constants_fallback.py
Normal file
21
aif/constants_fallback.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import parted # https://www.gnu.org/software/parted/api/index.html
|
||||||
|
|
||||||
|
|
||||||
|
ARCH_RELENG_KEY = '4AA4767BBC9C4B1D18AE28B77F2D434B9741E8AC'
|
||||||
|
VERSION = '0.2.0'
|
||||||
|
EXTERNAL_DEPS = ['blkinfo',
|
||||||
|
'gpg',
|
||||||
|
'lxml',
|
||||||
|
'mdstat',
|
||||||
|
'passlib',
|
||||||
|
'psutil',
|
||||||
|
'pyparted',
|
||||||
|
'pyroute2',
|
||||||
|
'pytz',
|
||||||
|
'requests',
|
||||||
|
'validators']
|
||||||
|
# PARTED FLAG INDEXING
|
||||||
|
PARTED_FSTYPES = sorted(list(dict(vars(parted.filesystem))['fileSystemType'].keys()))
|
||||||
|
PARTED_FLAGS = sorted(list(parted.partition.partitionFlag.values()))
|
||||||
|
PARTED_IDX_FLAG = dict(parted.partition.partitionFlag)
|
||||||
|
PARTED_FLAG_IDX = {v: k for k, v in PARTED_IDX_FLAG.items()}
|
@ -21,3 +21,8 @@ try:
|
|||||||
from . import mdadm_fallback
|
from . import mdadm_fallback
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from . import mdadm_fallback as mdadm
|
from . import mdadm_fallback as mdadm
|
||||||
|
|
||||||
|
try:
|
||||||
|
from . import _common
|
||||||
|
except ImportError:
|
||||||
|
pass # GI isn't supported, so we don't even use a fallback.
|
||||||
|
@ -2,8 +2,12 @@ import gi
|
|||||||
gi.require_version('BlockDev', '2.0')
|
gi.require_version('BlockDev', '2.0')
|
||||||
from gi.repository import BlockDev, GLib
|
from gi.repository import BlockDev, GLib
|
||||||
|
|
||||||
ps = BlockDev.PluginSpec()
|
BlockDev.ensure_init([None])
|
||||||
ps.name = BlockDev.Plugin.LVM
|
|
||||||
ps.so_name = "libbd_lvm.so"
|
|
||||||
|
|
||||||
BlockDev.init([ps])
|
|
||||||
|
def addBDPlugin(plugin_name):
|
||||||
|
plugins = BlockDev.get_available_plugin_names()
|
||||||
|
plugins.append(plugin_name)
|
||||||
|
plugins = list(set(plugins)) # Deduplicate
|
||||||
|
spec = BlockDev.plugin_specs_from_names(plugins)
|
||||||
|
return(BlockDev.ensure_init(spec))
|
||||||
|
@ -1,4 +1,133 @@
|
|||||||
from . import _common
|
import re
|
||||||
|
##
|
||||||
|
import parted
|
||||||
|
import psutil
|
||||||
|
##
|
||||||
|
import aif.constants
|
||||||
|
import aif.disk._common
|
||||||
|
import aif.utils
|
||||||
|
|
||||||
_BlockDev = _common.BlockDev
|
_BlockDev = aif.disk._common.BlockDev
|
||||||
|
|
||||||
|
|
||||||
|
class Partition(object):
|
||||||
|
def __init__(self, part_xml, diskobj, start_sector, partnum, tbltype, part_type = None):
|
||||||
|
# Belive it or not, dear reader, but this *entire method* is just to set attributes.
|
||||||
|
if tbltype not in ('gpt', 'msdos'):
|
||||||
|
raise ValueError('{0} must be one of gpt or msdos'.format(tbltype))
|
||||||
|
if tbltype == 'msdos' and part_type not in ('primary', 'extended', 'logical'):
|
||||||
|
raise ValueError(('You must specify if this is a '
|
||||||
|
'primary, extended, or logical partition for msdos partition tables'))
|
||||||
|
aif.disk._common.addBDPlugin('part')
|
||||||
|
self.xml = part_xml
|
||||||
|
self.id = part_xml.attrib['id']
|
||||||
|
self.table_type = getattr(_BlockDev.PartTableType, tbltype.upper())
|
||||||
|
if tbltype == 'msdos':
|
||||||
|
# Could technically be _BlockDev.PartTypeReq.NEXT buuuut that doesn't *quite* work
|
||||||
|
# with our project's structure.
|
||||||
|
if part_type == 'primary':
|
||||||
|
self.part_type = _BlockDev.PartTypeReq.NORMAL
|
||||||
|
elif part_type == 'extended':
|
||||||
|
self.part_type = _BlockDev.PartTypeReq.EXTENDED
|
||||||
|
elif part_type == 'logical':
|
||||||
|
self.part_type = _BlockDev.PartTypeReq.LOGICAL
|
||||||
|
self.flags = []
|
||||||
|
for f in self.xml.findall('partitionFlag'):
|
||||||
|
# *Technically* we could use e.g. getattr(_BlockDev.PartFlag, f.text.upper()), *but* we lose compat
|
||||||
|
# with parted's flags if we do that. :| So we do some funky logic both here and in the constants.
|
||||||
|
if f.text in aif.constants.PARTED_BD_MAP:
|
||||||
|
flag_id = aif.constants.BD_PART_FLAGS_FLAG_IDX[aif.constants.PARTED_BD_MAP[f.text]]
|
||||||
|
elif f.text in aif.constants.BD_PART_FLAGS_FRIENDLY:
|
||||||
|
flag_id = aif.constants.BD_PART_FLAGS_FLAG_IDX[aif.constants.BD_PART_FLAGS_FRIENDLY[f.text]]
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
self.flags.append(_BlockDev.PartFlag(flag_id))
|
||||||
|
self.partnum = partnum
|
||||||
|
self.fstype = self.xml.attrib['fsType'].lower()
|
||||||
|
if self.fstype not in aif.constants.PARTED_FSTYPES: # There isn't a way to do this with BlockDev? :|
|
||||||
|
raise ValueError(('{0} is not a valid partition filesystem type; '
|
||||||
|
'must be one of: {1}').format(self.xml.attrib['fsType'],
|
||||||
|
', '.join(sorted(aif.constants.PARTED_FSTYPES))))
|
||||||
|
self.disk = diskobj
|
||||||
|
self.device = self.disk.device # TODO: how to get this in libblockdev?
|
||||||
|
self.devpath = '{0}{1}'.format(self.device.path, partnum)
|
||||||
|
self.is_hiformatted = False
|
||||||
|
sizes = {}
|
||||||
|
for s in ('start', 'stop'):
|
||||||
|
x = dict(zip(('from_bgn', 'size', 'type'),
|
||||||
|
aif.utils.convertSizeUnit(self.xml.attrib[s])))
|
||||||
|
sectors = x['size']
|
||||||
|
if x['type'] == '%':
|
||||||
|
sectors = int(self.device.getLength() / x['size'])
|
||||||
|
else:
|
||||||
|
sectors = int(aif.utils.size.convertStorage(x['size'],
|
||||||
|
x['type'],
|
||||||
|
target = 'B') / self.device.sectorSize)
|
||||||
|
sizes[s] = (sectors, x['from_bgn'])
|
||||||
|
if sizes['start'][1] is not None:
|
||||||
|
if sizes['start'][1]:
|
||||||
|
self.begin = sizes['start'][0] + 0
|
||||||
|
else:
|
||||||
|
self.begin = self.device.getLength() - sizes['start'][0] # TODO: is there a way to get this in BD?
|
||||||
|
else:
|
||||||
|
self.begin = sizes['start'][0] + start_sector
|
||||||
|
if sizes['stop'][1] is not None:
|
||||||
|
if sizes['stop'][1]:
|
||||||
|
self.end = sizes['stop'][0] + 0
|
||||||
|
else:
|
||||||
|
# This *technically* should be - 34, at least for gpt, but the alignment optimizer fixes it for us.
|
||||||
|
self.end = (self.device.getLength() - 1) - sizes['stop'][0] # TODO: is there a way to get this in BD?
|
||||||
|
else:
|
||||||
|
self.end = self.begin + sizes['stop'][0]
|
||||||
|
# TECHNICALLY we could craft the Geometry object with "length = ...", but it doesn't let us be explicit
|
||||||
|
# in configs. So we manually crunch the numbers and do it all at the end.
|
||||||
|
# TODO: switch parted objects to BlockDev
|
||||||
|
# self.geometry = parted.Geometry(device = self.device,
|
||||||
|
# start = self.begin,
|
||||||
|
# end = self.end)
|
||||||
|
# self.filesystem = parted.FileSystem(type = self.fstype,
|
||||||
|
# geometry = self.geometry)
|
||||||
|
# self.partition = parted.Partition(disk = diskobj,
|
||||||
|
# type = self.part_type,
|
||||||
|
# geometry = self.geometry,
|
||||||
|
# fs = self.filesystem)
|
||||||
|
self.part_name = self.xml.attrib.get('name')
|
||||||
|
|
||||||
|
#
|
||||||
|
# def detect(self):
|
||||||
|
# pass # TODO; blkinfo?
|
||||||
|
|
||||||
|
|
||||||
|
class Disk(object):
|
||||||
|
def __init__(self, disk_xml):
|
||||||
|
# TODO: BlockDev.part.set_disk_flag(<disk>,
|
||||||
|
# BlockDev.PartDiskFlag(1),
|
||||||
|
# True) ??
|
||||||
|
# https://lazka.github.io/pgi-docs/BlockDev-2.0/enums.html#BlockDev.PartDiskFlag
|
||||||
|
# https://unix.stackexchange.com/questions/325886/bios-gpt-do-we-need-a-boot-flag
|
||||||
|
self.xml = disk_xml
|
||||||
|
self.devpath = self.xml.attrib['device']
|
||||||
|
self.is_lowformatted = None
|
||||||
|
self.is_hiformatted = None
|
||||||
|
self.is_partitioned = None
|
||||||
|
self.partitions = None
|
||||||
|
self._initDisk()
|
||||||
|
aif.disk._common.addBDPlugin('part')
|
||||||
|
|
||||||
|
def _initDisk(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def diskFormat(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def getPartitions(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def partFormat(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Mount(object):
|
||||||
|
def __init__(self, mount_xml, partobj):
|
||||||
|
pass
|
||||||
|
_common.addBDPlugin('fs')
|
||||||
|
@ -15,42 +15,12 @@ except ImportError:
|
|||||||
import parted # https://www.gnu.org/software/parted/api/index.html
|
import parted # https://www.gnu.org/software/parted/api/index.html
|
||||||
import psutil
|
import psutil
|
||||||
##
|
##
|
||||||
from aif.utils import xmlBool, size
|
import aif.constants
|
||||||
|
import aif.utils
|
||||||
|
|
||||||
# TODO: https://serverfault.com/questions/356534/ssd-erase-block-size-lvm-pv-on-raw-device-alignment
|
# TODO: https://serverfault.com/questions/356534/ssd-erase-block-size-lvm-pv-on-raw-device-alignment
|
||||||
|
|
||||||
|
|
||||||
PARTED_FSTYPES = sorted(list(dict(vars(parted.filesystem))['fileSystemType'].keys()))
|
|
||||||
PARTED_FLAGS = sorted(list(parted.partition.partitionFlag.values()))
|
|
||||||
IDX_FLAG = dict(parted.partition.partitionFlag)
|
|
||||||
FLAG_IDX = {v: k for k, v in IDX_FLAG.items()}
|
|
||||||
|
|
||||||
# parted lib can do SI or IEC. So can we.
|
|
||||||
_pos_re = re.compile((r'^(?P<pos_or_neg>-|\+)?\s*'
|
|
||||||
r'(?P<size>[0-9]+)\s*'
|
|
||||||
# empty means size in sectors
|
|
||||||
r'(?P<pct_unit_or_sct>%|{0}|)\s*$'.format('|'.join(size.valid_storage))
|
|
||||||
))
|
|
||||||
|
|
||||||
|
|
||||||
def convertSizeUnit(pos):
|
|
||||||
orig_pos = pos
|
|
||||||
pos = _pos_re.search(pos)
|
|
||||||
if pos:
|
|
||||||
pos_or_neg = (pos.group('pos_or_neg') if pos.group('pos_or_neg') else None)
|
|
||||||
if pos_or_neg == '+':
|
|
||||||
from_beginning = True
|
|
||||||
elif pos_or_neg == '-':
|
|
||||||
from_beginning = False
|
|
||||||
else:
|
|
||||||
from_beginning = pos_or_neg
|
|
||||||
_size = int(pos.group('size'))
|
|
||||||
amt_type = pos.group('pct_unit_or_sct').strip()
|
|
||||||
else:
|
|
||||||
raise ValueError('Invalid size specified: {0}'.format(orig_pos))
|
|
||||||
return((from_beginning, _size, amt_type))
|
|
||||||
|
|
||||||
|
|
||||||
class Partition(object):
|
class Partition(object):
|
||||||
def __init__(self, part_xml, diskobj, start_sector, partnum, tbltype, part_type = None):
|
def __init__(self, part_xml, diskobj, start_sector, partnum, tbltype, part_type = None):
|
||||||
if tbltype not in ('gpt', 'msdos'):
|
if tbltype not in ('gpt', 'msdos'):
|
||||||
@ -59,10 +29,10 @@ class Partition(object):
|
|||||||
raise ValueError(('You must specify if this is a '
|
raise ValueError(('You must specify if this is a '
|
||||||
'primary, extended, or logical partition for msdos partition tables'))
|
'primary, extended, or logical partition for msdos partition tables'))
|
||||||
self.xml = part_xml
|
self.xml = part_xml
|
||||||
self.id = part_xml.attrib['id']
|
self.id = self.xml.attrib['id']
|
||||||
self.flags = set()
|
self.flags = set()
|
||||||
for f in self.xml.findall('partitionFlag'):
|
for f in self.xml.findall('partitionFlag'):
|
||||||
if f.text in PARTED_FLAGS:
|
if f.text in aif.constants.PARTED_FLAGS:
|
||||||
self.flags.add(f.text)
|
self.flags.add(f.text)
|
||||||
self.flags = sorted(list(self.flags))
|
self.flags = sorted(list(self.flags))
|
||||||
self.partnum = partnum
|
self.partnum = partnum
|
||||||
@ -77,10 +47,10 @@ class Partition(object):
|
|||||||
else:
|
else:
|
||||||
self.part_type = parted.PARTITION_NORMAL
|
self.part_type = parted.PARTITION_NORMAL
|
||||||
self.fstype = self.xml.attrib['fsType'].lower()
|
self.fstype = self.xml.attrib['fsType'].lower()
|
||||||
if self.fstype not in PARTED_FSTYPES:
|
if self.fstype not in aif.constants.PARTED_FSTYPES:
|
||||||
raise ValueError(('{0} is not a valid partition filesystem type; '
|
raise ValueError(('{0} is not a valid partition filesystem type; '
|
||||||
'must be one of: {1}').format(self.xml.attrib['fsType'],
|
'must be one of: {1}').format(self.xml.attrib['fsType'],
|
||||||
', '.join(sorted(PARTED_FSTYPES))))
|
', '.join(sorted(aif.constants.PARTED_FSTYPES))))
|
||||||
self.disk = diskobj
|
self.disk = diskobj
|
||||||
self.device = self.disk.device
|
self.device = self.disk.device
|
||||||
self.devpath = '{0}{1}'.format(self.device.path, partnum)
|
self.devpath = '{0}{1}'.format(self.device.path, partnum)
|
||||||
@ -88,12 +58,14 @@ class Partition(object):
|
|||||||
sizes = {}
|
sizes = {}
|
||||||
for s in ('start', 'stop'):
|
for s in ('start', 'stop'):
|
||||||
x = dict(zip(('from_bgn', 'size', 'type'),
|
x = dict(zip(('from_bgn', 'size', 'type'),
|
||||||
convertSizeUnit(self.xml.attrib[s])))
|
aif.utils.convertSizeUnit(self.xml.attrib[s])))
|
||||||
sectors = x['size']
|
sectors = x['size']
|
||||||
if x['type'] == '%':
|
if x['type'] == '%':
|
||||||
sectors = int(self.device.getLength() / x['size'])
|
sectors = int(self.device.getLength() / x['size'])
|
||||||
else:
|
else:
|
||||||
sectors = int(size.convertStorage(x['size'], x['type'], target = 'B') / self.device.sectorSize)
|
sectors = int(aif.utils.size.convertStorage(x['size'],
|
||||||
|
x['type'],
|
||||||
|
target = 'B') / self.device.sectorSize)
|
||||||
sizes[s] = (sectors, x['from_bgn'])
|
sizes[s] = (sectors, x['from_bgn'])
|
||||||
if sizes['start'][1] is not None:
|
if sizes['start'][1] is not None:
|
||||||
if sizes['start'][1]:
|
if sizes['start'][1]:
|
||||||
@ -122,7 +94,7 @@ class Partition(object):
|
|||||||
geometry = self.geometry,
|
geometry = self.geometry,
|
||||||
fs = self.filesystem)
|
fs = self.filesystem)
|
||||||
for f in self.flags[:]:
|
for f in self.flags[:]:
|
||||||
flag_id = FLAG_IDX[f]
|
flag_id = aif.constants.PARTED_FLAG_IDX[f]
|
||||||
if self.partition.isFlagAvailable(flag_id):
|
if self.partition.isFlagAvailable(flag_id):
|
||||||
self.partition.setFlag(flag_id)
|
self.partition.setFlag(flag_id)
|
||||||
else:
|
else:
|
||||||
@ -133,16 +105,20 @@ class Partition(object):
|
|||||||
# https://github.com/dcantrell/pyparted/issues/65
|
# https://github.com/dcantrell/pyparted/issues/65
|
||||||
# self.partition.name = self.xml.attrib.get('name')
|
# self.partition.name = self.xml.attrib.get('name')
|
||||||
_pedpart = self.partition.getPedPartition()
|
_pedpart = self.partition.getPedPartition()
|
||||||
_pedpart.set_name(self.xml.attrib.get('name'))
|
_pedpart.set_name(self.xml.attrib['name'])
|
||||||
|
#
|
||||||
def detect(self):
|
# def detect(self):
|
||||||
pass
|
# pass # TODO; blkinfo?
|
||||||
|
|
||||||
|
|
||||||
class Disk(object):
|
class Disk(object):
|
||||||
def __init__(self, disk_xml):
|
def __init__(self, disk_xml):
|
||||||
self.xml = disk_xml
|
self.xml = disk_xml
|
||||||
self.devpath = self.xml.attrib['device']
|
self.devpath = self.xml.attrib['device']
|
||||||
|
self.is_lowformatted = None
|
||||||
|
self.is_hiformatted = None
|
||||||
|
self.is_partitioned = None
|
||||||
|
self.partitions = None
|
||||||
self._initDisk()
|
self._initDisk()
|
||||||
|
|
||||||
def _initDisk(self):
|
def _initDisk(self):
|
||||||
@ -221,6 +197,7 @@ class Disk(object):
|
|||||||
self.is_partitioned = True
|
self.is_partitioned = True
|
||||||
return()
|
return()
|
||||||
|
|
||||||
|
|
||||||
class Mount(object):
|
class Mount(object):
|
||||||
def __init__(self, mount_xml, partobj):
|
def __init__(self, mount_xml, partobj):
|
||||||
self.xml = mount_xml
|
self.xml = mount_xml
|
||||||
|
33
aif/utils.py
33
aif/utils.py
@ -1,9 +1,13 @@
|
|||||||
import os
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
def hasBin(binary_name):
|
def hasBin(binary_name):
|
||||||
paths = []
|
paths = []
|
||||||
for p in os.environ.get('PATH', '/usr/bin:/bin').split(':'):
|
for p in os.environ.get('PATH', '/usr/bin:/bin').split(':'):
|
||||||
os.listdir(os.path.realpath(p))
|
if binary_name in os.listdir(os.path.realpath(p)):
|
||||||
|
return(os.path.join(p, binary_name))
|
||||||
|
return(False)
|
||||||
|
|
||||||
|
|
||||||
def xmlBool(xmlobj):
|
def xmlBool(xmlobj):
|
||||||
@ -181,3 +185,30 @@ class _Sizer(object):
|
|||||||
|
|
||||||
|
|
||||||
size = _Sizer()
|
size = _Sizer()
|
||||||
|
|
||||||
|
|
||||||
|
# We do this as base level so they aren't compiled on every invocation/instantiation.
|
||||||
|
# parted lib can do SI or IEC. So can we.
|
||||||
|
_pos_re = re.compile((r'^(?P<pos_or_neg>-|\+)?\s*'
|
||||||
|
r'(?P<size>[0-9]+)\s*'
|
||||||
|
# empty means size in sectors
|
||||||
|
r'(?P<pct_unit_or_sct>%|{0}|)\s*$'.format('|'.join(size.valid_storage))
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
def convertSizeUnit(pos):
|
||||||
|
orig_pos = pos
|
||||||
|
pos = _pos_re.search(pos)
|
||||||
|
if pos:
|
||||||
|
pos_or_neg = (pos.group('pos_or_neg') if pos.group('pos_or_neg') else None)
|
||||||
|
if pos_or_neg == '+':
|
||||||
|
from_beginning = True
|
||||||
|
elif pos_or_neg == '-':
|
||||||
|
from_beginning = False
|
||||||
|
else:
|
||||||
|
from_beginning = pos_or_neg
|
||||||
|
_size = int(pos.group('size'))
|
||||||
|
amt_type = pos.group('pct_unit_or_sct').strip()
|
||||||
|
else:
|
||||||
|
raise ValueError('Invalid size specified: {0}'.format(orig_pos))
|
||||||
|
return((from_beginning, _size, amt_type))
|
||||||
|
Loading…
Reference in New Issue
Block a user