@ -7,14 +7,14 @@ import site
from calculate . vars . datavars import Variable , Namespace , HashVariable , \
TableVariable , IniCreated , DefaultValue
from calculate . vars . alt_datavars import NamespaceNode , VariableNode , \
StringType, ListType, IntegerType , \
FloatType , IniType
ListType, IntegerType , \
FloatType , IniType , TableType
from calculate . utils . gentoo import ProfileWalker
from calculate . utils . fs import readFile
from calculate . utils . files import list_directory
from pyparsing import Literal , Word , ZeroOrMore , Group , Optional , restOfLine , \
empty , printables , OneOrMore , lineno , line , col , SkipTo , \
LineEnd , Combine
LineEnd , Combine , nums
from enum import Enum
@ -46,17 +46,27 @@ class CalculateIniParser:
comment = comment_symbol + Optional ( restOfLine )
section_name = Word ( printables + ' \t ' , excludeChars = ' [] ' )
section_name = ( lbrack . suppress ( ) + ( ~ Word ( nums )
+ Word ( printables + ' \t ' ,
excludeChars = ' [] ' ) )
+ rbrack . suppress ( ) )
value_name = Word ( printables + ' \t ' , excludeChars = ' =-+ ' )
# non_comma = Word(printables+'\t', excludeChars=',')
clear_section = lbrack . suppress ( ) + Group ( empty ) + rbrack . suppress ( )
row_index = lbrack . suppress ( ) + Word ( nums ) + rbrack . suppress ( )
section_start = Group ( OneOrMore ( lbrack . suppress ( ) + section_name
+ rbrack . suppress ( ) )
+ ( clear_section | ~ lbrack ( ) )
+ LineEnd ( ) . suppress ( ) )
namespace_start = Group ( OneOrMore ( section_name )
+ ( clear_section | ~ lbrack )
+ LineEnd ( ) . suppress ( ) )
table_start = Group ( OneOrMore ( section_name )
+ ( row_index | clear_section | ~ lbrack )
+ LineEnd ( ) . suppress ( ) )
section_start = ( namespace_start ( ' namespace ' ) |
table_start ( ' table ' ) )
# Если содержимое ini-файла не предваряется заголовком секции,
# значит эта строка ошибочна.
@ -80,6 +90,38 @@ class CalculateIniParser:
| unexpected )
self . ini_section_parser . ignore ( comment )
def parse ( self , data : str ) :
for tokens , start , end in self . ini_section_parser . scanString ( data ) :
if tokens . getName ( ) == " error " :
continue
section , defkeys = tokens
print ( ' section type: {} ' . format ( section . getName ( ) ) )
if section . getName ( ) == ' namespace ' :
section_list = section . asList ( )
if section_list [ - 1 ] == [ ] :
yield { ' clear_section ' : ( section_list [ : - 1 ] , ) }
else :
yield { ' start_section ' : ( section_list , ) }
for defkey in defkeys :
if defkey . getName ( ) == " error " :
continue
yield { ' define_key ' : ( defkey [ 0 ] , defkey [ 2 ] ,
self . operations [ defkey [ 1 ] ] ) }
else :
table_list = section . asList ( )
if table_list [ - 1 ] == [ ] :
yield { ' clear_table ' : ( table_list [ : - 1 ] , ) }
else :
table_values = { }
for defkey in defkeys :
if defkey . getName ( ) == " error " :
continue
table_values . update ( { defkey [ 0 ] : defkey [ 2 ] } )
yield { ' start_table ' : ( table_list , table_values ) }
def _unexpected_token ( self , string , location , tokens ) :
''' Метод вызываемый парсером, если обнаружена некорректная строка,
предназначен для получения некорректной строки и е е дальнейшего
@ -95,36 +137,21 @@ class CalculateIniParser:
self . _errors = [ ]
return errors
def parse ( self , data ) :
for tokens , start , end in self . ini_section_parser . scanString ( data ) :
if tokens . getName ( ) == " error " :
continue
section , defkeys = tokens
section_list = section . asList ( )
if section_list [ - 1 ] == [ ] :
yield { ' clear_section ' : ( section_list [ : - 1 ] , ) }
else :
yield { ' start_section ' : ( section . asList ( ) , ) }
for defkey in defkeys :
if defkey . getName ( ) == " error " :
continue
yield { ' define_key ' : ( section . asList ( ) , defkey [ 0 ] , defkey [ 2 ] ,
self . operations [ defkey [ 1 ] ] ) }
class NamespaceIniFiller :
''' Класс, предназначенный для наполнения Namespace объекта переменными
из calculate . ini файла . '''
def __init__ ( self ) :
available_sections = { ' custom ' }
def __init__ ( self , restrict_creation = True ) :
self . ini_parser = CalculateIniParser ( )
self . restricted = restrict_creation
self . modify_only = False
def error ( self , lineno , error_message ) :
self . errors . append ( lineno , error_message )
def fill ( self , namespace , ini_file_text ):
def fill ( self , namespace : NamespaceNode , ini_file_text : str ) - > None :
''' Метод для разбора calculate.ini файла и добавления всех е г о
переменных в указанное пространство имен . '''
self . namespace = namespace
@ -136,68 +163,152 @@ class NamespaceIniFiller:
def _line_processor ( self , start_section = None ,
clear_section = None ,
start_table = None ,
clear_table = None ,
define_key = None ,
error = None , * * kwargs ) :
if start_section is not None :
self . start_section ( * start_section )
elif clear_section is not None :
self . clear_section ( * clear_section )
elif start_table is not None :
self . start_table ( * start_table )
elif clear_table is not None :
self . clear_table ( * clear_table )
elif define_key is not None :
self . define_key ( * define_key )
for error in self . ini_parser . errors :
self . set_error ( * error )
def start_section ( self , sections ):
def start_section ( self , sections : str ) - > None :
''' Метод для получения доступа и создания пространств имен. '''
if self . restricted :
self . modify_only = sections [ 0 ] not in self . available_sections
self . current_namespace = self . namespace
for section in sections :
if section not in self . current_namespace . namespaces :
self . current_namespace . add_namespace ( NamespaceNode ( section ) )
if not self . modify_only :
self . current_namespace . add_namespace (
NamespaceNode ( section ) )
else :
self . current_namespace = None
return
self . current_namespace = self . current_namespace . namespaces [ section ]
def clear_section ( self , sections ) :
def clear_section ( self , sections : list ) - > None :
''' Метод для очистки пространства имен. '''
current_namespace = self . namespace
for section in sections :
if section not in current_namespace . namespaces :
if section in current_namespace . namespaces :
current_namespace = current_namespace . namespaces [ section ]
elif ( section in current_namespace . variables and
current_namespace . variables [ section ] . variable_type
is TableType ) :
table_variable = current_namespace . variables [ section ]
table_to_clear = table_variable . get_value ( )
table_to_clear . clear ( )
table_variable . source = table_to_clear
else :
return
current_namespace = current_namespace . namespaces [ section ]
current_namespace . clear ( )
def change_value ( self , key , value ) :
def start_table ( self , sections : str , row ) - > None :
''' Метод для создания и модификации таблиц. '''
if self . restricted :
self . modify_only = sections [ 0 ] not in self . available_sections
self . current_namespace = self . namespace
row_number = int ( sections . pop ( ) )
table_name = sections . pop ( )
for section in sections :
if section not in self . current_namespace . namespaces :
if not self . modify_only :
self . current_namespace . add_namespace (
NamespaceNode ( section ) )
else :
self . current_namespace = None
return
self . current_namespace = self . current_namespace . namespaces [ section ]
if table_name not in self . current_namespace . variables :
if not self . modify_only :
table_variable = VariableNode ( table_name ,
self . current_namespace ,
variable_type = TableType ,
source = [ row ] )
else :
table_variable = self . current_namespace . variables [ table_name ]
table = table_variable . get_value ( )
if len ( table ) < row_number :
table . change_row ( row , row_number )
else :
table . add_row ( row )
table_variable . source = table
def define_key ( self , key : str , value : str , optype ) - > None :
if self . current_namespace is None :
return
if optype == Define . assign :
if key not in self . current_namespace :
self . define_variable ( key , value )
else :
self . change_value ( key , value )
elif optype == Define . append :
if key not in self . current_namespace :
self . define_variable ( key , value )
else :
self . append_value ( key , value )
elif optype == Define . remove :
if key not in self . current_namespace :
self . define_variable ( key , value )
else :
self . remove_value ( key , value )
def change_value ( self , key : str , value : str ) - > None :
''' Метод для изменения значения переменной. '''
variable = self . current_namespace [ key ]
variable . source = value
def define_variable ( self , key , value ) :
def define_variable ( self , key : str , value : str ) - > None :
''' Метод для создания переменных в calculate.ini файле. '''
print ( " define variable: ' {} ' with value: ' {} ' " . format ( key , value ) )
VariableNode ( key , self . current_namespace , variable_type = IniType ,
source = value )
if not self . modify_only :
VariableNode ( key , self . current_namespace , variable_type = IniType ,
source = value )
else :
# TODO Какая-то обработка ошибки.
pass
def append_value ( self , key , value ) :
def append_value ( self , key : str , value : str ) - > None :
''' Метод выполняющий действия возложенные на оператор +=. '''
variable = self . current_namespace [ key ]
variable_value = variable . get_value ( )
if variable . variable_type is IniType :
value_list = value . split ( ' , ' )
variable_list = variable_value . split ( ' , ' )
for item in value_list :
if item not in variable_list :
variable_list . append ( item . strip ( ) )
variable_value = ' , ' . join ( variable_list )
elif variable . variable_type is ListType :
value_list = value . split ( ' , ' )
for item in value_list :
if item not in variable_value :
variable_value . append ( item . strip ( ) )
elif variable . variable_type is IntegerType :
variable_value + = int ( value )
elif variable . variable_type is FloatType :
variable_value + = float ( value )
variable . source = variable_value
def remove_value ( self , key , value ) :
def remove_value ( self , key : str , value : str ) - > None :
''' Метод выполняющий действия возложенные на оператор -=. '''
variable = self . current_namespace [ key ]
variable_value = variable . get_value ( )
@ -225,24 +336,8 @@ class NamespaceIniFiller:
variable . source = variable_value
def define_key ( self , section , key , value , optype ) :
if optype == Define . assign :
if key not in self . current_namespace :
self . define_variable ( key , value )
else :
self . change_value ( key , value )
elif optype == Define . append :
if key not in self . current_namespace :
self . define_variable ( key , value )
else :
self . append_value ( key , value )
elif optype == Define . remove :
if key not in self . current_namespace :
self . define_variable ( key , value )
else :
self . remove_value ( key , value )
def set_error ( self , line , lineno , col ) :
''' Метод для добавления ошибки в лог. '''
self . error ( lineno , " Syntax error: {} " . format ( line ) )