Update / Fix
- add comments wipe feature - fix arg doc - update Readme - add corresponding unitest (manual check :-/)
This commit is contained in:
@@ -8,4 +8,4 @@ You should have received a copy of the license along with this
|
||||
work. If not, see <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
"""
|
||||
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "0.3.2"
|
||||
@@ -116,7 +116,7 @@ class ChaChaSimpleINI_section(ChaChaSimpleINI_section_Base):
|
||||
"""
|
||||
return "[{0}]".format(self.name)
|
||||
|
||||
def formatAll(self,bBeautify:bool = False) -> str:
|
||||
def formatAll(self,bBeautify:bool = False,bWipeComments:bool = False) -> str:
|
||||
"""
|
||||
Output the full formated Section's.
|
||||
Example:
|
||||
@@ -126,6 +126,7 @@ class ChaChaSimpleINI_section(ChaChaSimpleINI_section_Base):
|
||||
...
|
||||
|
||||
:param bool bBeautify: enable space arround '='
|
||||
:param bool bWipeComments: do not write comments
|
||||
:return: formated string
|
||||
:rtype: str
|
||||
"""
|
||||
@@ -135,7 +136,7 @@ class ChaChaSimpleINI_section(ChaChaSimpleINI_section_Base):
|
||||
for key in self.ar_keys:
|
||||
if(isinstance(key,ChaChaSimpleINI_key)):
|
||||
result = result + key.format(bBeautify) + "\n"
|
||||
elif(isinstance(key,ChaChaSimpleINI_key_Comment)):
|
||||
elif isinstance(key,ChaChaSimpleINI_key_Comment) and (bWipeComments==False):
|
||||
result = result + key.format()+ "\n"
|
||||
elif(isinstance(key,ChaChaSimpleINI_key_Blank)):
|
||||
result = result + "\n"
|
||||
@@ -358,8 +359,8 @@ class ChaChaSimpleINI:
|
||||
This is the object representing an INI file.
|
||||
|
||||
:param str filepath: INI file path
|
||||
:type index: str or None
|
||||
:param bool bForceAlwaysOutputArrays: Force API to always return an array even with one single Key/Section
|
||||
:param bool bStrict: raise exception if unsupported formated line found
|
||||
:return: The INI file
|
||||
:rtype: ChaChaSimpleINI
|
||||
:raises: FileNotFoundError
|
||||
@@ -370,8 +371,9 @@ class ChaChaSimpleINI:
|
||||
self.bForceAlwaysOutputArrays = bForceAlwaysOutputArrays
|
||||
self.ar_sections=[]
|
||||
self.ar_tmp_sections=[]
|
||||
self.sectioncomment_tag=";"
|
||||
self.bStrict = bStrict
|
||||
#self.sectioncomment_tag=";"
|
||||
self.sectioncomment_tags=[";","#"]
|
||||
|
||||
self.ar_sections.append(ChaChaSimpleINI_section_Root(bForceAlwaysOutputArrays))
|
||||
|
||||
@@ -382,31 +384,36 @@ class ChaChaSimpleINI:
|
||||
line = _line.rstrip()
|
||||
if result := re.search(r'^\s*$',line):
|
||||
self.ar_tmp_sections.append(ChaChaSimpleINI_section_Blank())
|
||||
elif result := re.search(r'^\s*{0}(?P<section_comment>.*)'.format(self.sectioncomment_tag),line):
|
||||
self.ar_tmp_sections.append(ChaChaSimpleINI_section_Comment(self.sectioncomment_tag,result.group('section_comment').strip()))
|
||||
elif result := re.search(r'^\s*\[(?P<section_name>.*)\]\s*$',line):
|
||||
#attach tmp Comments/Blanks sections to main Sections list
|
||||
self.ar_sections.extend(self.ar_tmp_sections)
|
||||
self.ar_tmp_sections = []
|
||||
self.addSection(result.group('section_name').strip())
|
||||
elif result := re.search(r'^\s*(?P<key_name>[^=]*)=(?P<key_value>.*)',line):
|
||||
#searching last Section (not comment nor Blank) in mains Sections list
|
||||
_section = None
|
||||
for section in reversed(self.ar_sections) :
|
||||
if isinstance(section, ChaChaSimpleINI_section):
|
||||
_section = section
|
||||
break
|
||||
#attach tmp Comments/Blanks Sections to Key
|
||||
for section in self.ar_tmp_sections:
|
||||
if isinstance(section, ChaChaSimpleINI_section_Blank):
|
||||
_section.appendBlankKey()
|
||||
elif isinstance(section, ChaChaSimpleINI_section_Comment):
|
||||
_section.appendCommentKey(self.sectioncomment_tag,section.value)
|
||||
self.ar_tmp_sections = []
|
||||
_section.appendKey(result.group('key_name').strip(),result.group('key_value').strip())
|
||||
else:
|
||||
if bStrict:
|
||||
raise ChaChaINI_WrongFormatException("Found on line: {0}".format(lineIndex))
|
||||
bCommentLine = False
|
||||
for _commentpatern in self.sectioncomment_tags:
|
||||
if result := re.search(r'^\s*{0}(?P<section_comment>.*)'.format(_commentpatern),line):
|
||||
self.ar_tmp_sections.append(ChaChaSimpleINI_section_Comment(_commentpatern,result.group('section_comment').strip()))
|
||||
bCommentLine=True
|
||||
if not bCommentLine:
|
||||
if result := re.search(r'^\s*\[(?P<section_name>.*)\]\s*$',line):
|
||||
#attach tmp Comments/Blanks sections to main Sections list
|
||||
self.ar_sections.extend(self.ar_tmp_sections)
|
||||
self.ar_tmp_sections = []
|
||||
self.addSection(result.group('section_name').strip())
|
||||
elif result := re.search(r'^\s*(?P<key_name>[^=]*)=(?P<key_value>.*)',line):
|
||||
#searching last Section (not comment nor Blank) in mains Sections list
|
||||
_section = None
|
||||
for section in reversed(self.ar_sections) :
|
||||
if isinstance(section, ChaChaSimpleINI_section):
|
||||
_section = section
|
||||
break
|
||||
#attach tmp Comments/Blanks Sections to Key
|
||||
for section in self.ar_tmp_sections:
|
||||
if isinstance(section, ChaChaSimpleINI_section_Blank):
|
||||
_section.appendBlankKey()
|
||||
elif isinstance(section, ChaChaSimpleINI_section_Comment):
|
||||
_section.appendCommentKey(section.delimiter,section.value)
|
||||
self.ar_tmp_sections = []
|
||||
_section.appendKey(result.group('key_name').strip(),result.group('key_value').strip())
|
||||
else:
|
||||
if bStrict:
|
||||
raise ChaChaINI_WrongFormatException("Found on line: {0}".format(lineIndex))
|
||||
lineIndex = lineIndex + 1
|
||||
if self.ar_tmp_sections:
|
||||
self.ar_sections.extend(self.ar_tmp_sections)
|
||||
@@ -423,22 +430,23 @@ class ChaChaSimpleINI:
|
||||
"""
|
||||
self.filepath = filepath
|
||||
|
||||
def formatAll(self,bBeautify:bool = False) -> str:
|
||||
def formatAll(self,bBeautify:bool = False,bWipeComments:bool = False) -> str:
|
||||
"""
|
||||
Generate the full formated output.
|
||||
:param bool bBeautify: enable space arround '='
|
||||
:param bool bWipeComments: do not write comments
|
||||
:return: formated string
|
||||
:rtype: str
|
||||
"""
|
||||
result = ""
|
||||
for section in self.ar_sections:
|
||||
if isinstance(section,ChaChaSimpleINI_section):
|
||||
_result = section.formatAll(bBeautify)
|
||||
_result = section.formatAll(bBeautify,bWipeComments)
|
||||
if _result:
|
||||
if bBeautify:
|
||||
_result = _result + "\n"
|
||||
result = result + _result
|
||||
elif isinstance(section,ChaChaSimpleINI_section_Comment):
|
||||
elif isinstance(section,ChaChaSimpleINI_section_Comment) and (bWipeComments==False):
|
||||
_result = section.formatAll()
|
||||
if _result:
|
||||
_result = _result + "\n"
|
||||
@@ -516,16 +524,17 @@ class ChaChaSimpleINI:
|
||||
self.ar_sections.append(section)
|
||||
return section
|
||||
|
||||
def writeFile(self,bBeautify:bool = False) -> None:
|
||||
def writeFile(self,bBeautify:bool = False,bWipeComments:bool = False) -> None:
|
||||
"""
|
||||
actually write the INI object to the file.
|
||||
|
||||
:param bool bBeautify: enable beautify mode (more spaces and newlines)
|
||||
:param bool bWipeComments: do not write comments
|
||||
:return: Nothing
|
||||
:rtype: None
|
||||
"""
|
||||
with open(self.filepath,'w') as file:
|
||||
file.write(self.formatAll(bBeautify))
|
||||
file.write(self.formatAll(bBeautify,bWipeComments))
|
||||
|
||||
def getAllSectionNames(self) -> list[str]:
|
||||
"""
|
||||
|
||||
37
README.md
37
README.md
@@ -1,8 +1,8 @@
|
||||
# ChaCha-INI
|
||||
|
||||
***Yet another python INI parser / generator !***
|
||||
*** Yet another python INI parser / generator ! ***
|
||||
|
||||
This one aim to be simple and initilaly target Unreal Tournament Series config files, but should work well for other usages.
|
||||
This one aim to be simple and initially targets Unreal Tournament Serie's configuration files, but aim to work on most ini implementation.
|
||||
|
||||
# key features
|
||||
- handling multiple Sections instance with same name
|
||||
@@ -10,10 +10,11 @@ This one aim to be simple and initilaly target Unreal Tournament Series config f
|
||||
- generate output INI with or without spaces around '='
|
||||
- strict mode: detect missformed INI files
|
||||
- blank lines and comments are kept
|
||||
- Wipe comments
|
||||
|
||||
# Limitations
|
||||
- Comments and blank lines can only be add in order
|
||||
- Multiple sections with same name are supported for existing files but can not be added by API
|
||||
- Multiple sections with same name are supported for existing files but can not be added through API
|
||||
|
||||
# Installation
|
||||
**From main repository:**
|
||||
@@ -21,33 +22,43 @@ This one aim to be simple and initilaly target Unreal Tournament Series config f
|
||||
python3 -m pip install git+https://chacha.ddns.net/gitea/chacha/ChaChaSimpleINI
|
||||
|
||||
|
||||
|
||||
**From PIP:**
|
||||
|
||||
TODO :-/
|
||||
|
||||
# Usage
|
||||
**Input INI:**
|
||||
|
||||
;MyIni File
|
||||
[section1]
|
||||
key1=12
|
||||
|
||||
**code:**
|
||||
|
||||
from ChaChaSimpleINI import *
|
||||
|
||||
MyINI = ChaChaSimpleINI("~/myINI.ini")
|
||||
key1 = MyINI.getKeyValue("section1","key1")
|
||||
print(key1) # will output 12
|
||||
MyINI.setAddKeyValue("section1","key2",42)
|
||||
MyINI.writeFile(False)
|
||||
|
||||
key1 = MyINI.getKeyValue("section1","key1") # open: [section1], get: key1=<???> value
|
||||
print(key1) # will output 12
|
||||
|
||||
MyINI.setAddKeyValue("section1","key2",42) # open: [section1], set: key2=<???> value
|
||||
MyINI.writeFile(False) # write the file without beautify option
|
||||
|
||||
MyINI.setFilePath("~/myINI_nocomments.ini") # set a new output file target
|
||||
MyINI.writeFile(False) # write the file without beautify option and without comments
|
||||
|
||||
**Output INI:**
|
||||
|
||||
/> cat ~/myINI.ini
|
||||
|
||||
;MyIni File
|
||||
[section1]
|
||||
key1=12
|
||||
key2=42
|
||||
|
||||
/> cat ~/myINI_nocomments.ini
|
||||
|
||||
[section1]
|
||||
key1=12
|
||||
key2=42
|
||||
|
||||
|
||||
To see more advanced examples, refer to the included unittest code.
|
||||
|
||||
# Copyright
|
||||
|
||||
@@ -230,4 +230,14 @@ class Test_ChaChaSimpleINI_base(unittest.TestCase):
|
||||
with self.assertRaises(ChaChaINI_WrongFormatException):
|
||||
testini = ChaChaSimpleINI("testfiles/test_strict.ini",False,True)
|
||||
|
||||
testini = ChaChaSimpleINI("testfiles/test_strict.ini",False,False)
|
||||
testini = ChaChaSimpleINI("testfiles/test_strict.ini",False,False)
|
||||
|
||||
def test_samba(self):
|
||||
testini = ChaChaSimpleINI("testfiles/test_smb.conf")
|
||||
testini.setFilePath("tmp/test_smb.ini")
|
||||
testini.writeFile(False,False)
|
||||
testini.setFilePath("tmp/test_smb_wiped.ini")
|
||||
testini.writeFile(False,True)
|
||||
testini=None
|
||||
pass
|
||||
|
||||
223
Tests/testfiles/test_smb.conf
Normal file
223
Tests/testfiles/test_smb.conf
Normal file
@@ -0,0 +1,223 @@
|
||||
# This is the main Samba configuration file. You should read the
|
||||
# smb.conf(5) manual page in order to understand the options listed
|
||||
# here. Samba has a huge number of configurable options (perhaps too
|
||||
# many!) most of which are not shown in this example
|
||||
#
|
||||
# For a step to step guide on installing, configuring and using samba,
|
||||
# read the Samba-HOWTO-Collection. This may be obtained from:
|
||||
# http://www.samba.org/samba/docs/Samba-HOWTO-Collection.pdf
|
||||
#
|
||||
# Many working examples of smb.conf files can be found in the
|
||||
# Samba-Guide which is generated daily and can be downloaded from:
|
||||
# http://www.samba.org/samba/docs/Samba-Guide.pdf
|
||||
#
|
||||
# Any line which starts with a ; (semi-colon) or a # (hash)
|
||||
# is a comment and is ignored. In this example we will use a #
|
||||
# for commentry and a ; for parts of the config file that you
|
||||
# may wish to enable
|
||||
#
|
||||
# NOTE: Whenever you modify this file you should run the command "testparm"
|
||||
# to check that you have not made any basic syntactic errors.
|
||||
#
|
||||
#======================= Global Settings =====================================
|
||||
[global]
|
||||
|
||||
# workgroup = NT-Domain-Name or Workgroup-Name, eg: MIDEARTH
|
||||
workgroup = MYGROUP
|
||||
|
||||
# server string is the equivalent of the NT Description field
|
||||
server string = Samba Server
|
||||
|
||||
# Server role. Defines in which mode Samba will operate. Possible
|
||||
# values are "standalone server", "member server", "classic primary
|
||||
# domain controller", "classic backup domain controller", "active
|
||||
# directory domain controller".
|
||||
#
|
||||
# Most people will want "standalone sever" or "member server".
|
||||
# Running as "active directory domain controller" will require first
|
||||
# running "samba-tool domain provision" to wipe databases and create a
|
||||
# new domain.
|
||||
server role = standalone server
|
||||
|
||||
# This option is important for security. It allows you to restrict
|
||||
# connections to machines which are on your local network. The
|
||||
# following example restricts access to two C class networks and
|
||||
# the "loopback" interface. For more examples of the syntax see
|
||||
# the smb.conf man page
|
||||
; hosts allow = 192.168.1. 192.168.2. 127.
|
||||
|
||||
# Uncomment this if you want a guest account, you must add this to /etc/passwd
|
||||
# otherwise the user "nobody" is used
|
||||
; guest account = pcguest
|
||||
|
||||
# this tells Samba to use a separate log file for each machine
|
||||
# that connects
|
||||
log file = /usr/local/samba/var/log.%m
|
||||
|
||||
# Put a capping on the size of the log files (in Kb).
|
||||
max log size = 50
|
||||
|
||||
# Specifies the Kerberos or Active Directory realm the host is part of
|
||||
; realm = MY_REALM
|
||||
|
||||
# Backend to store user information in. New installations should
|
||||
# use either tdbsam or ldapsam. smbpasswd is available for backwards
|
||||
# compatibility. tdbsam requires no further configuration.
|
||||
; passdb backend = tdbsam
|
||||
|
||||
# Using the following line enables you to customise your configuration
|
||||
# on a per machine basis. The %m gets replaced with the netbios name
|
||||
# of the machine that is connecting.
|
||||
# Note: Consider carefully the location in the configuration file of
|
||||
# this line. The included file is read at that point.
|
||||
; include = /usr/local/samba/lib/smb.conf.%m
|
||||
|
||||
# Configure Samba to use multiple interfaces
|
||||
# If you have multiple network interfaces then you must list them
|
||||
# here. See the man page for details.
|
||||
; interfaces = 192.168.12.2/24 192.168.13.2/24
|
||||
|
||||
# Where to store roving profiles (only for Win95 and WinNT)
|
||||
# %L substitutes for this servers netbios name, %U is username
|
||||
# You must uncomment the [Profiles] share below
|
||||
; logon path = \\%L\Profiles\%U
|
||||
|
||||
# Windows Internet Name Serving Support Section:
|
||||
# WINS Support - Tells the NMBD component of Samba to enable it's WINS Server
|
||||
; wins support = yes
|
||||
|
||||
# WINS Server - Tells the NMBD components of Samba to be a WINS Client
|
||||
# Note: Samba can be either a WINS Server, or a WINS Client, but NOT both
|
||||
; wins server = w.x.y.z
|
||||
|
||||
# WINS Proxy - Tells Samba to answer name resolution queries on
|
||||
# behalf of a non WINS capable client, for this to work there must be
|
||||
# at least one WINS Server on the network. The default is NO.
|
||||
; wins proxy = yes
|
||||
|
||||
# DNS Proxy - tells Samba whether or not to try to resolve NetBIOS names
|
||||
# via DNS nslookups. The default is NO.
|
||||
dns proxy = no
|
||||
|
||||
# These scripts are used on a domain controller or stand-alone
|
||||
# machine to add or delete corresponding unix accounts
|
||||
; add user script = /usr/sbin/useradd %u
|
||||
; add group script = /usr/sbin/groupadd %g
|
||||
; add machine script = /usr/sbin/adduser -n -g machines -c Machine -d /dev/null -s /bin/false %u
|
||||
; delete user script = /usr/sbin/userdel %u
|
||||
; delete user from group script = /usr/sbin/deluser %u %g
|
||||
; delete group script = /usr/sbin/groupdel %g
|
||||
|
||||
|
||||
#============================ Share Definitions ==============================
|
||||
[homes]
|
||||
comment = Home Directories
|
||||
browseable = no
|
||||
writable = yes
|
||||
|
||||
# Un-comment the following and create the netlogon directory for Domain Logons
|
||||
; [netlogon]
|
||||
; comment = Network Logon Service
|
||||
; path = /usr/local/samba/lib/netlogon
|
||||
; guest ok = yes
|
||||
; writable = no
|
||||
; share modes = no
|
||||
|
||||
|
||||
# Un-comment the following to provide a specific roving profile share
|
||||
# the default is to use the user's home directory
|
||||
;[Profiles]
|
||||
; path = /usr/local/samba/profiles
|
||||
; browseable = no
|
||||
; guest ok = yes
|
||||
|
||||
|
||||
# NOTE: If you have a BSD-style print system there is no need to
|
||||
# specifically define each individual printer
|
||||
[printers]
|
||||
comment = All Printers
|
||||
path = /usr/spool/samba
|
||||
browseable = no
|
||||
# Set public = yes to allow user 'guest account' to print
|
||||
guest ok = no
|
||||
writable = no
|
||||
printable = yes
|
||||
|
||||
# This one is useful for people to share files
|
||||
;[tmp]
|
||||
; comment = Temporary file space
|
||||
; path = /tmp
|
||||
; read only = no
|
||||
; public = yes
|
||||
|
||||
# A publicly accessible directory, but read only, except for people in
|
||||
# the "staff" group
|
||||
;[public]
|
||||
; comment = Public Stuff
|
||||
; path = /home/samba
|
||||
; public = yes
|
||||
; writable = no
|
||||
; printable = no
|
||||
; write list = @staff
|
||||
|
||||
# Other examples.
|
||||
#
|
||||
# A private printer, usable only by fred. Spool data will be placed in fred's
|
||||
# home directory. Note that fred must have write access to the spool directory,
|
||||
# wherever it is.
|
||||
;[fredsprn]
|
||||
; comment = Fred's Printer
|
||||
; valid users = fred
|
||||
; path = /homes/fred
|
||||
; printer = freds_printer
|
||||
; public = no
|
||||
; writable = no
|
||||
; printable = yes
|
||||
|
||||
# A private directory, usable only by fred. Note that fred requires write
|
||||
# access to the directory.
|
||||
;[fredsdir]
|
||||
; comment = Fred's Service
|
||||
; path = /usr/somewhere/private
|
||||
; valid users = fred
|
||||
; public = no
|
||||
; writable = yes
|
||||
; printable = no
|
||||
|
||||
# a service which has a different directory for each machine that connects
|
||||
# this allows you to tailor configurations to incoming machines. You could
|
||||
# also use the %U option to tailor it by user name.
|
||||
# The %m gets replaced with the machine name that is connecting.
|
||||
;[pchome]
|
||||
; comment = PC Directories
|
||||
; path = /usr/pc/%m
|
||||
; public = no
|
||||
; writable = yes
|
||||
|
||||
# A publicly accessible directory, read/write to all users. Note that all files
|
||||
# created in the directory by users will be owned by the default user, so
|
||||
# any user with access can delete any other user's files. Obviously this
|
||||
# directory must be writable by the default user. Another user could of course
|
||||
# be specified, in which case all files would be owned by that user instead.
|
||||
;[public]
|
||||
; path = /usr/somewhere/else/public
|
||||
; public = yes
|
||||
; only guest = yes
|
||||
; writable = yes
|
||||
; printable = no
|
||||
|
||||
# The following two entries demonstrate how to share a directory so that two
|
||||
# users can place files there that will be owned by the specific users. In this
|
||||
# setup, the directory should be writable by both users and should have the
|
||||
# sticky bit set on it to prevent abuse. Obviously this could be extended to
|
||||
# as many users as required.
|
||||
;[myshare]
|
||||
; comment = Mary's and Fred's stuff
|
||||
; path = /usr/somewhere/shared
|
||||
; valid users = mary fred
|
||||
; public = no
|
||||
; writable = yes
|
||||
; printable = no
|
||||
; create mask = 0765
|
||||
|
||||
|
||||
Reference in New Issue
Block a user