Rocksolid Light

Welcome to novaBBS (click a section below)

mail  files  register  newsreader  groups  login

Message-ID:  

If the facts don't fit the theory, change the facts. -- Albert Einstein


devel / comp.lang.python / When is logging.getLogger(__name__) needed?

SubjectAuthor
* When is logging.getLogger(__name__) needed?Loris Bennett
+* Re: When is logging.getLogger(__name__) needed?Peter Otten
|`- Re: When is logging.getLogger(__name__) needed?Loris Bennett
+* Re: When is logging.getLogger(__name__) needed?dn
|`* Re: When is logging.getLogger(__name__) needed?Loris Bennett
| `* Re: When is logging.getLogger(__name__) needed?Loris Bennett
|  `- Re: When is logging.getLogger(__name__) needed?dn
`- Re: When is logging.getLogger(__name__) needed?dn

1
When is logging.getLogger(__name__) needed?

<877cux2hy0.fsf@hornfels.zedat.fu-berlin.de>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=22701&group=comp.lang.python#22701

  copy link   Newsgroups: comp.lang.python
Path: i2pn2.org!i2pn.org!news.swapon.de!fu-berlin.de!uni-berlin.de!not-for-mail
From: loris.be...@fu-berlin.de (Loris Bennett)
Newsgroups: comp.lang.python
Subject: When is logging.getLogger(__name__) needed?
Date: Fri, 31 Mar 2023 15:01:27 +0200
Organization: ZEDAT, Freie Universität Berlin
Lines: 59
Message-ID: <877cux2hy0.fsf@hornfels.zedat.fu-berlin.de>
Mime-Version: 1.0
Content-Type: text/plain
X-Trace: news.uni-berlin.de QZCFIvYQg5qOIjb0VuYA4wg0ZGqxecEWZebnNsGKk4TA+p
Cancel-Lock: sha1:1XQfBODyNCrMulSo0UH/Os9GEoM=
User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.1 (gnu/linux)
 by: Loris Bennett - Fri, 31 Mar 2023 13:01 UTC

Hi,

In my top level program file, main.py, I have

def main_function():

parser = argparse.ArgumentParser(description="my prog")

...

args = parser.parse_args()
config = configparser.ConfigParser()

if args.config_file is None:
config_file = DEFAULT_CONFIG_FILE
else:
config_file = args.config_file

config.read(config_file)

logging.config.fileConfig(fname=config_file)
logger = logging.getLogger(__name__)

do_some_stuff()

my_class_instance = myprog.MyClass()

def do_some_stuff():

logger.info("Doing stuff")

This does not work, because 'logger' is not known in the function
'do_some_stuff'.

However, if in 'my_prog/my_class.py' I have

class MyClass:

def __init__(self):

logger.debug("created instance of MyClass")

this 'just works'.

I can add

logger = logging.getLogger(__name__)

to 'do_some_stuff', but why is this necessary in this case but not in
the class?

Or should I be doing this entirely differently?

Cheers,

Loris

--
This signature is currently under constuction.

Re: When is logging.getLogger(__name__) needed?

<mailman.2474.1680276873.20444.python-list@python.org>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=22705&group=comp.lang.python#22705

  copy link   Newsgroups: comp.lang.python
Path: i2pn2.org!i2pn.org!news.swapon.de!fu-berlin.de!uni-berlin.de!not-for-mail
From: __pete...@web.de (Peter Otten)
Newsgroups: comp.lang.python
Subject: Re: When is logging.getLogger(__name__) needed?
Date: Fri, 31 Mar 2023 17:34:31 +0200
Lines: 85
Message-ID: <mailman.2474.1680276873.20444.python-list@python.org>
References: <877cux2hy0.fsf@hornfels.zedat.fu-berlin.de>
<3783122a-28d9-776d-b4d1-979cb1d3ac1d@web.de>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: quoted-printable
X-Trace: news.uni-berlin.de pEs6okdh4wPNesg8KkZU9gm4IM6xmiYkkMFKyyrRoaIQ==
Return-Path: <__peter__@web.de>
X-Original-To: python-list@python.org
Delivered-To: python-list@mail.python.org
Authentication-Results: mail.python.org; dkim=pass
reason="2048-bit key; unprotected key"
header.d=web.de header.i=__peter__@web.de header.b=s3wuusaV;
dkim-adsp=pass; dkim-atps=neutral
X-Spam-Status: OK 0.003
X-Spam-Evidence: '*H*': 0.99; '*S*': 0.00; 'def': 0.04; 'traceback':
0.04; '(most': 0.05; 'last):': 0.05; 'received:212.227': 0.07;
'binding': 0.09; 'else:': 0.09; 'subject:needed': 0.09; 'bennett':
0.16; 'from:addr:web.de': 0.16; 'instance': 0.16; 'message-
id:@web.de': 0.16; 'none:': 0.16; 'received:mout.web.de': 0.16;
'received:web.de': 0.16; 'wrote:': 0.16; 'problem': 0.16;
'probably': 0.17; 'to:addr:python-list': 0.20; 'skip:_ 10': 0.22;
'code': 0.23; 'received:de': 0.23; 'local': 0.27; 'function':
0.27; '>>>': 0.28; 'header:User-Agent:1': 0.30; 'module': 0.31;
'program': 0.31; '"",': 0.32; 'but': 0.32; 'header:In-Reply-To:1':
0.34; 'work,': 0.36; "skip:' 10": 0.37; "it's": 0.37; 'class':
0.37; 'received:192.168': 0.37; 'file': 0.38; 'necessary': 0.39;
'want': 0.40; 'received:212': 0.62; 'subject:(': 0.64; 'your':
0.64; 'top': 0.65; 'look': 0.65; 'global': 0.73; "you'll": 0.73;
'known': 0.84; 'so:': 0.84; 'visibility': 0.84
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=web.de; s=s29768273;
t=1680276870; i=__peter__@web.de;
bh=Yt5DtWmo/06YBlGNM3ffqFPd8KTsaEA/JShlQqzNpU0=;
h=X-UI-Sender-Class:Date:Subject:To:References:From:In-Reply-To;
b=s3wuusaVvyPA97EOtwS5yH4lHgfLoPHRS3hN/R316+w4+Bz1VhLllty5+HsVOqE0x
TYwynSIxUi/20grVRPCSgDWm01v/wrYRYKYTrzButaR669dlhXvfNGlzYiO9qXsWOs
bVLbbjsA+cYhUvnMRR8l1ByAiDJEuKbWVyiwS7jvPwX39Qf1e1iNe16tlspQQ+B2QE
dpS6JfpGrdLuR7RGZdnM6AIrfXfcArsC9xKYTxGl8sqrArPqVeHd0OBWfQlPARcgFz
CmFojPqUqnHPCTJbRLN7BYqnp+OaZyXHmOoErzIlp8ix9QsgPXEJiekp3+y+1D2yDM
OuH1+cE6SrJsQ==
X-UI-Sender-Class: 814a7b36-bfc1-4dae-8640-3722d8ec6cd6
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:102.0) Gecko/20100101
Thunderbird/102.9.0
Content-Language: en-US
In-Reply-To: <877cux2hy0.fsf@hornfels.zedat.fu-berlin.de>
X-Provags-ID: V03:K1:RYItgoP1LPFDSTCMPtyqIKMq++kF4g6mYkVRfUcRjaQ4HHz1bDy
tGuE1VpepuYdDqZMhUWOuOXrkeD9MBGynGAqfCGDxYPy8WomZC4hz7b4r0qo62n5wCMhKLa
kQAh8682svw1uIAjWOMhVRGHlyByygjl2Oo9QGl7vBANXlw+VIDJ8RO4sbEUYXnCLTj1B3f
972QenwvXYldXC7tyF/tg==
X-Spam-Flag: NO
UI-OutboundReport: notjunk:1;M01:P0:4pjeXZtTmAM=;mNtjq+pYv0DtydxpCbxTWmwEWm8
yIc3CMR5dHlwgr2NsHNfzHtyXI5I+Lk4OwKiyRy9wruTUDw7f4hAjmoCz/GgtCz83lYANByvi
voiXwsR8SVRPvXx2KYbnEoVoM/ejd3rBj1UnGHazkBBYpHQ5sOIdbwRyelMbralXIFbrgdfVF
norZYSXKBk1XW9jjf5fWUoml1DB66QkqWfRzrr8l93ZelaB648TaFhi51pJtcCG83uDis/eSQ
XlEj3tk1Lcjwp1/myN/WXUZ6sx0zQNmccNaCLTdzoXVSnKQeGhMxNGapjhi5ATNPZXVhZhSqJ
LXGK51O8BrxmnG3I+DVRVc2K4PQDekkoZCEqVRflTc51xouezGjXHAyjRRWHq+FVewaxE4wU9
+Uo+QGXmkuujrJ6LgxgPQ5Ny0WVmPGvPmXbxls+U8MzziSiz8WMjHSq4eTZu412tCd0UKlaXN
BfhPQuzy0gCOTaTrNFOPVKJ2Rq5O/Ber+WIgr8XDNpzZ3Jo+Hy+CoWvH508YqrjXqa/TQrr0t
WFozpfFtVQvSsPY0hBcz95vOgq8UPcaelsrW1/WvxG4AnvktbEUcpDvSzm6FFYvEMjkD0/Qcz
/wuYRcyD+hxPTVMxvHP08vsO9Roi2UxcO1aE1w2YIIN64WwZvqyH43lrOvF5n5dDSSAom8u4D
1H+5afO/owCnCMDEvTvxz0+KFpXcNsizTgdA5ptYnh0r1xFbkcUFaIKq+pUmV+zFjES7slGhD
7gH6jpUeybiH/Rs8heeLqCmufUZwo8KnGNM6ff9nJaLVm6HVMg/mREn4S9tzT7STYT1cZI+Da
z48eGISFiYJzTE8/5R6T3pUrbDpK/O8iYiVzmxJYkj8ry9nCfwXA4ztjJsSfYDE4wTDTDW4Cx
TuuvcJAptlSSSzInYLwlLxKhWtSnNSXHPFZVce1cvOkcl+HdZq5hct6FOz1XMht65v8Eux4Vw
HSiODw==
X-BeenThere: python-list@python.org
X-Mailman-Version: 2.1.39
Precedence: list
List-Id: General discussion list for the Python programming language
<python-list.python.org>
List-Unsubscribe: <https://mail.python.org/mailman/options/python-list>,
<mailto:python-list-request@python.org?subject=unsubscribe>
List-Archive: <https://mail.python.org/pipermail/python-list/>
List-Post: <mailto:python-list@python.org>
List-Help: <mailto:python-list-request@python.org?subject=help>
List-Subscribe: <https://mail.python.org/mailman/listinfo/python-list>,
<mailto:python-list-request@python.org?subject=subscribe>
X-Mailman-Original-Message-ID: <3783122a-28d9-776d-b4d1-979cb1d3ac1d@web.de>
X-Mailman-Original-References: <877cux2hy0.fsf@hornfels.zedat.fu-berlin.de>
 by: Peter Otten - Fri, 31 Mar 2023 15:34 UTC

On 31/03/2023 15:01, Loris Bennett wrote:
> Hi,
>
> In my top level program file, main.py, I have
>
> def main_function():
>
> parser = argparse.ArgumentParser(description="my prog")
>
> ...
>
> args = parser.parse_args()
> config = configparser.ConfigParser()
>
> if args.config_file is None:
> config_file = DEFAULT_CONFIG_FILE
> else:
> config_file = args.config_file
>
> config.read(config_file)
>
> logging.config.fileConfig(fname=config_file)
> logger = logging.getLogger(__name__)
>
> do_some_stuff()
>
> my_class_instance = myprog.MyClass()
>
> def do_some_stuff():
>
> logger.info("Doing stuff")
>
> This does not work, because 'logger' is not known in the function
> 'do_some_stuff'.
>
> However, if in 'my_prog/my_class.py' I have
>
> class MyClass:
>
> def __init__(self):
>
> logger.debug("created instance of MyClass")
>
> this 'just works'.

Take another look at your code -- you'll probably find

> logger = logging.getLogger(__name__)

on the module level in my_class.py.

> to 'do_some_stuff', but why is this necessary in this case but not in
> the class?

Your problem has nothing to do with logging -- it's about visibility
("scope") of names:

>>> def use_name():
print(name)

>>> def define_name():
name = "Loris"

>>> use_name()
Traceback (most recent call last):
File "<pyshell#56>", line 1, in <module>
use_name()
File "<pyshell#52>", line 2, in use_name
print(name)
NameError: name 'name' is not defined

Binding (=assigning to) a name inside a function makes it local to that
function. If you want a global (module-level) name you have to say so:

>>> def define_name():
global name
name = "Peter"

>>> define_name()
>>> use_name()
Peter

Re: When is logging.getLogger(__name__) needed?

<mailman.2483.1680301344.20444.python-list@python.org>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=22716&group=comp.lang.python#22716

  copy link   Newsgroups: comp.lang.python
Path: i2pn2.org!i2pn.org!weretis.net!feeder8.news.weretis.net!newsreader4.netcologne.de!news.netcologne.de!fu-berlin.de!uni-berlin.de!not-for-mail
From: PythonL...@DancesWithMice.info (dn)
Newsgroups: comp.lang.python
Subject: Re: When is logging.getLogger(__name__) needed?
Date: Sat, 1 Apr 2023 11:20:26 +1300
Organization: DWM
Lines: 95
Message-ID: <mailman.2483.1680301344.20444.python-list@python.org>
References: <877cux2hy0.fsf@hornfels.zedat.fu-berlin.de>
<dd184814-69cb-3ce7-57f2-8e22eb8a02cf@DancesWithMice.info>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
X-Trace: news.uni-berlin.de /jBt2ydFmpyJ00+Lr9ehIgwxBxJN3xHEtubouGKsBirw==
Return-Path: <PythonList@DancesWithMice.info>
X-Original-To: python-list@python.org
Delivered-To: python-list@mail.python.org
Authentication-Results: mail.python.org; dkim=pass
reason="2048-bit key; unprotected key"
header.d=danceswithmice.info header.i=@danceswithmice.info
header.b=Ekm6QLsa; dkim-adsp=pass; dkim-atps=neutral
X-Spam-Status: OK 0.042
X-Spam-Evidence: '*H*': 0.92; '*S*': 0.00; 'def': 0.04; 'url:courses':
0.07; '=dn': 0.09; 'else:': 0.09; 'example.': 0.09;
'from:addr:danceswithmice.info': 0.09; 'from:addr:pythonlist':
0.09; "shouldn't": 0.09; 'subject:needed': 0.09; '...,': 0.16;
'applies:': 0.16; 'bennett': 0.16; 'constraint,': 0.16;
'convention,': 0.16; 'instance': 0.16; 'message-
id:@DancesWithMice.info': 0.16; 'none:': 0.16; 'received:51.254':
0.16; 'received:51.254.211': 0.16; 'received:51.254.211.219':
0.16; 'received:cloud': 0.16; 'received:rangi.cloud': 0.16;
'wrote:': 0.16; 'to:addr:python-list': 0.20; 'option': 0.20;
'input': 0.21; 'purposes': 0.22; 'skip:_ 10': 0.22; 'url:wiki':
0.23; '(and': 0.25; 'configure': 0.26; 'creating': 0.27;
'function': 0.27; 'header:User-Agent:1': 0.30; 'whole': 0.30;
'header:Organization:1': 0.31; 'program': 0.31; 'split': 0.32;
'words,': 0.32; 'received:192.168.1': 0.32; 'but': 0.32; 'there':
0.33; 'able': 0.34; 'header:In-Reply-To:1': 0.34; 'url:edu': 0.36;
'work,': 0.36; 'change': 0.36; "skip:' 10": 0.37; 'class': 0.37;
'received:192.168': 0.37; 'could': 0.38; 'two': 0.39; 'necessary':
0.39; 'developers': 0.39; 'should': 0.40; 'url-ip:104.21/16':
0.61; 'url:pdf': 0.62; 'once': 0.63; 'personal': 0.64; 'becomes':
0.64; 'received:51': 0.64; 'subject:(': 0.64; 'thus': 0.64; 'top':
0.65; 'earlier': 0.67; 'items': 0.68; 'within': 0.69; 'establish':
0.70; 'url-ip:208.80.154/24': 0.70; 'url-ip:208.80/16': 0.70;
'url:wikipedia': 0.70; 'url-ip:208/8': 0.71; 'global': 0.73;
'head': 0.73; 'demand': 0.75; 'url-ip:209/8': 0.76; 'known': 0.84;
'complement': 0.84; 'debate': 0.84; 'establishes': 0.84;
'feature,': 0.84; 'url:people': 0.84; 'affect': 0.91
DKIM-Filter: OpenDKIM Filter v2.11.0 vps.rangi.cloud BD0D07297
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=danceswithmice.info;
s=staff; t=1680301337;
bh=DvKgJuAgbI1mUNSva05xh6UdORDM9+SKYPt7jTsGU+s=;
h=Date:Subject:To:References:From:In-Reply-To:From;
b=Ekm6QLsaUt/JKRlVuJM97S24CvsP1wC30Sljou4jqUsoQhgPRxX2gGkT9o5Ektw9p
/xj/x6Rcr100kBMgW4NctEXmPENPdzpakERqBouNs7mmwzR3jBVAz8/2INBwOTWTAY
2ntqq+IjlH8v2k+KPiJG7d80GxV+u+q3gMQdqI5fev7WbK3JaM/gXI1ktW5yVEMqbF
yUh+FjUNrogCdCGufHgNZTfpuGZE1aw9BaKXVTjBuvAj6foP1YFAvQvFn2B1RK0EuN
2CNipQAH2Ou7N97m/uAX6LYopiMlDkZO5jojTBx0c6d1U73QS67GLt6Jx7sMDKLX/I
uGbvAkQQEQpuw==
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
Thunderbird/102.8.0
Content-Language: en-GB
In-Reply-To: <877cux2hy0.fsf@hornfels.zedat.fu-berlin.de>
X-BeenThere: python-list@python.org
X-Mailman-Version: 2.1.39
Precedence: list
List-Id: General discussion list for the Python programming language
<python-list.python.org>
List-Unsubscribe: <https://mail.python.org/mailman/options/python-list>,
<mailto:python-list-request@python.org?subject=unsubscribe>
List-Archive: <https://mail.python.org/pipermail/python-list/>
List-Post: <mailto:python-list@python.org>
List-Help: <mailto:python-list-request@python.org?subject=help>
List-Subscribe: <https://mail.python.org/mailman/listinfo/python-list>,
<mailto:python-list-request@python.org?subject=subscribe>
X-Mailman-Original-Message-ID: <dd184814-69cb-3ce7-57f2-8e22eb8a02cf@DancesWithMice.info>
X-Mailman-Original-References: <877cux2hy0.fsf@hornfels.zedat.fu-berlin.de>
 by: dn - Fri, 31 Mar 2023 22:20 UTC

On 01/04/2023 02.01, Loris Bennett wrote:
> Hi,
>
> In my top level program file, main.py, I have
>
> def main_function():
>
> parser = argparse.ArgumentParser(description="my prog")
>
> ...
>
> args = parser.parse_args()
> config = configparser.ConfigParser()
>
> if args.config_file is None:
> config_file = DEFAULT_CONFIG_FILE
> else:
> config_file = args.config_file
>
> config.read(config_file)
>
> logging.config.fileConfig(fname=config_file)
> logger = logging.getLogger(__name__)
>
> do_some_stuff()
>
> my_class_instance = myprog.MyClass()
>
> def do_some_stuff():
>
> logger.info("Doing stuff")
>
> This does not work, because 'logger' is not known in the function
> 'do_some_stuff'.
>
> However, if in 'my_prog/my_class.py' I have
>
> class MyClass:
>
> def __init__(self):
>
> logger.debug("created instance of MyClass")
>
> this 'just works'.
>
> I can add
>
> logger = logging.getLogger(__name__)
>
> to 'do_some_stuff', but why is this necessary in this case but not in
> the class?
>
> Or should I be doing this entirely differently?

Yes: differently.

To complement @Peter's response, two items for consideration:

1 once main_function() has completed, have it return logger and other
such values/constructs. The target-identifiers on the LHS of the
function-call will thus be within the global scope.

2 if the purposes of main_function() are condensed-down to a few
(English, or ..., language) phrases, the word "and" will feature, eg
- configure env according to cmdLN args,
- establish log(s),
- do_some_stuff(), ** AND **
- instantiate MyClass.

If these (and do_some_stuff(), like MyClass' methods) were split into
separate functions* might you find it easier to see them as separate
sub-solutions? Each sub-solution would be able to contribute to the
whole - the earlier ones as creating (outputting) a description,
constraint, or basis; which becomes input to a later function/method.

* there is some debate amongst developers about whether "one function,
one purpose" should be a rule, a convention, or tossed in the trash. YMMV!

Personal view: SOLID's "Single" principle applies: there should be only
one reason (hanging over the head of each method/function, like the
Sword of Damocles) for it to change - or one 'user' who could demand a
change to that function. In other words, an updated cmdLN option
shouldn't affect a function which establishes logging, for example.

Web.Refs:
https://people.engr.tamu.edu/choe/choe/courses/20fall/315/lectures/slide23-solid.pdf
https://www.hanselminutes.com/145/solid-principles-with-uncle-bob-robert-c-martin
https://idioms.thefreedictionary.com/sword+of+Damocles
https://en.wikipedia.org/wiki/Damocles

--
Regards,
=dn

Re: When is logging.getLogger(__name__) needed?

<mailman.2484.1680301366.20444.python-list@python.org>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=22717&group=comp.lang.python#22717

  copy link   Newsgroups: comp.lang.python
Path: i2pn2.org!i2pn.org!news.swapon.de!fu-berlin.de!uni-berlin.de!not-for-mail
From: PythonL...@DancesWithMice.info (dn)
Newsgroups: comp.lang.python
Subject: Re: When is logging.getLogger(__name__) needed?
Date: Sat, 1 Apr 2023 11:20:26 +1300
Organization: DWM
Lines: 95
Message-ID: <mailman.2484.1680301366.20444.python-list@python.org>
References: <877cux2hy0.fsf@hornfels.zedat.fu-berlin.de>
<dd184814-69cb-3ce7-57f2-8e22eb8a02cf@DancesWithMice.info>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
X-Trace: news.uni-berlin.de rs49NgFlsbirFcZ6COm74QQasZEzmlJQnGIc+4OFz+qg==
Return-Path: <PythonList@DancesWithMice.info>
X-Original-To: python-list@python.org
Delivered-To: python-list@mail.python.org
Authentication-Results: mail.python.org; dkim=pass
reason="2048-bit key; unprotected key"
header.d=danceswithmice.info header.i=@danceswithmice.info
header.b=nTrOV5I/; dkim-adsp=pass; dkim-atps=neutral
X-Spam-Status: OK 0.042
X-Spam-Evidence: '*H*': 0.92; '*S*': 0.00; 'def': 0.04; 'url:courses':
0.07; '=dn': 0.09; 'else:': 0.09; 'example.': 0.09;
'from:addr:danceswithmice.info': 0.09; 'from:addr:pythonlist':
0.09; "shouldn't": 0.09; 'subject:needed': 0.09; '...,': 0.16;
'applies:': 0.16; 'bennett': 0.16; 'constraint,': 0.16;
'convention,': 0.16; 'instance': 0.16; 'message-
id:@DancesWithMice.info': 0.16; 'none:': 0.16; 'received:51.254':
0.16; 'received:51.254.211': 0.16; 'received:51.254.211.219':
0.16; 'received:cloud': 0.16; 'received:rangi.cloud': 0.16;
'wrote:': 0.16; 'to:addr:python-list': 0.20; 'option': 0.20;
'input': 0.21; 'purposes': 0.22; 'skip:_ 10': 0.22; 'url:wiki':
0.23; '(and': 0.25; 'configure': 0.26; 'creating': 0.27;
'function': 0.27; 'header:User-Agent:1': 0.30; 'whole': 0.30;
'header:Organization:1': 0.31; 'program': 0.31; 'split': 0.32;
'words,': 0.32; 'received:192.168.1': 0.32; 'but': 0.32; 'there':
0.33; 'able': 0.34; 'header:In-Reply-To:1': 0.34; 'url:edu': 0.36;
'work,': 0.36; 'change': 0.36; "skip:' 10": 0.37; 'class': 0.37;
'received:192.168': 0.37; 'could': 0.38; 'two': 0.39; 'necessary':
0.39; 'developers': 0.39; 'should': 0.40; 'url-ip:104.21/16':
0.61; 'url:pdf': 0.62; 'once': 0.63; 'personal': 0.64; 'becomes':
0.64; 'received:51': 0.64; 'subject:(': 0.64; 'thus': 0.64; 'top':
0.65; 'earlier': 0.67; 'items': 0.68; 'within': 0.69; 'establish':
0.70; 'url-ip:208.80.154/24': 0.70; 'url-ip:208.80/16': 0.70;
'url:wikipedia': 0.70; 'url-ip:208/8': 0.71; 'global': 0.73;
'head': 0.73; 'demand': 0.75; 'url-ip:209/8': 0.76; 'known': 0.84;
'complement': 0.84; 'debate': 0.84; 'establishes': 0.84;
'feature,': 0.84; 'url:people': 0.84; 'affect': 0.91
DKIM-Filter: OpenDKIM Filter v2.11.0 vps.rangi.cloud C8CDB72D7
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=danceswithmice.info;
s=staff; t=1680301364;
bh=DvKgJuAgbI1mUNSva05xh6UdORDM9+SKYPt7jTsGU+s=;
h=Date:Subject:To:References:From:In-Reply-To:From;
b=nTrOV5I/tHe4w8zJxhz20eZZe5VDcapGJssmJxxKGEEi0yqilfiuzKLtCMO3dlzU7
oG3maSu86dJGNsesd5LR2BbA0O98lgWo5MznnzcHWbycFS6YZyQXpaWRqb3D3Izvhi
sYccdvPGnhuazgvnKLipKwf0exuToAHxCMp8WouLuYgsZeibuIA2EPQnfXQ90F0cdt
uIE34+k+JgXHVHh9/Jg/GxiwpFzbWMIyvJ0j/GEG+pFr7Hhr9Q07L1AsV58Z6zEy1s
32dmqTaC4jdiCX8KsxiL8ojegAGWXD+iudfJQ8oVecKy7e7WB/CeaV+knwVpN+je4Y
eEvURuETG0icQ==
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
Thunderbird/102.8.0
Content-Language: en-GB
In-Reply-To: <877cux2hy0.fsf@hornfels.zedat.fu-berlin.de>
X-BeenThere: python-list@python.org
X-Mailman-Version: 2.1.39
Precedence: list
List-Id: General discussion list for the Python programming language
<python-list.python.org>
List-Unsubscribe: <https://mail.python.org/mailman/options/python-list>,
<mailto:python-list-request@python.org?subject=unsubscribe>
List-Archive: <https://mail.python.org/pipermail/python-list/>
List-Post: <mailto:python-list@python.org>
List-Help: <mailto:python-list-request@python.org?subject=help>
List-Subscribe: <https://mail.python.org/mailman/listinfo/python-list>,
<mailto:python-list-request@python.org?subject=subscribe>
X-Mailman-Original-Message-ID: <dd184814-69cb-3ce7-57f2-8e22eb8a02cf@DancesWithMice.info>
X-Mailman-Original-References: <877cux2hy0.fsf@hornfels.zedat.fu-berlin.de>
 by: dn - Fri, 31 Mar 2023 22:20 UTC

On 01/04/2023 02.01, Loris Bennett wrote:
> Hi,
>
> In my top level program file, main.py, I have
>
> def main_function():
>
> parser = argparse.ArgumentParser(description="my prog")
>
> ...
>
> args = parser.parse_args()
> config = configparser.ConfigParser()
>
> if args.config_file is None:
> config_file = DEFAULT_CONFIG_FILE
> else:
> config_file = args.config_file
>
> config.read(config_file)
>
> logging.config.fileConfig(fname=config_file)
> logger = logging.getLogger(__name__)
>
> do_some_stuff()
>
> my_class_instance = myprog.MyClass()
>
> def do_some_stuff():
>
> logger.info("Doing stuff")
>
> This does not work, because 'logger' is not known in the function
> 'do_some_stuff'.
>
> However, if in 'my_prog/my_class.py' I have
>
> class MyClass:
>
> def __init__(self):
>
> logger.debug("created instance of MyClass")
>
> this 'just works'.
>
> I can add
>
> logger = logging.getLogger(__name__)
>
> to 'do_some_stuff', but why is this necessary in this case but not in
> the class?
>
> Or should I be doing this entirely differently?

Yes: differently.

To complement @Peter's response, two items for consideration:

1 once main_function() has completed, have it return logger and other
such values/constructs. The target-identifiers on the LHS of the
function-call will thus be within the global scope.

2 if the purposes of main_function() are condensed-down to a few
(English, or ..., language) phrases, the word "and" will feature, eg
- configure env according to cmdLN args,
- establish log(s),
- do_some_stuff(), ** AND **
- instantiate MyClass.

If these (and do_some_stuff(), like MyClass' methods) were split into
separate functions* might you find it easier to see them as separate
sub-solutions? Each sub-solution would be able to contribute to the
whole - the earlier ones as creating (outputting) a description,
constraint, or basis; which becomes input to a later function/method.

* there is some debate amongst developers about whether "one function,
one purpose" should be a rule, a convention, or tossed in the trash. YMMV!

Personal view: SOLID's "Single" principle applies: there should be only
one reason (hanging over the head of each method/function, like the
Sword of Damocles) for it to change - or one 'user' who could demand a
change to that function. In other words, an updated cmdLN option
shouldn't affect a function which establishes logging, for example.

Web.Refs:
https://people.engr.tamu.edu/choe/choe/courses/20fall/315/lectures/slide23-solid.pdf
https://www.hanselminutes.com/145/solid-principles-with-uncle-bob-robert-c-martin
https://idioms.thefreedictionary.com/sword+of+Damocles
https://en.wikipedia.org/wiki/Damocles

--
Regards,
=dn

Re: When is logging.getLogger(__name__) needed?

<87edozamfz.fsf@debian-BULLSEYE-live-builder-AMD64>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=22809&group=comp.lang.python#22809

  copy link   Newsgroups: comp.lang.python
Path: i2pn2.org!i2pn.org!weretis.net!feeder8.news.weretis.net!news.szaf.org!fu-berlin.de!uni-berlin.de!not-for-mail
From: loris.be...@fu-berlin.de (Loris Bennett)
Newsgroups: comp.lang.python
Subject: Re: When is logging.getLogger(__name__) needed?
Date: Tue, 04 Apr 2023 13:58:24 +0200
Organization: ZEDAT, Freie Universität Berlin
Lines: 77
Message-ID: <87edozamfz.fsf@debian-BULLSEYE-live-builder-AMD64>
References: <877cux2hy0.fsf@hornfels.zedat.fu-berlin.de>
<3783122a-28d9-776d-b4d1-979cb1d3ac1d@web.de>
<mailman.2474.1680276873.20444.python-list@python.org>
Mime-Version: 1.0
Content-Type: text/plain
X-Trace: news.uni-berlin.de b/sZ5LlDZy1Sw4FYyuwOPwvg+NGNVzrjmYYQCs6HnIJsGP
Cancel-Lock: sha1:h6qg3vqOCjNTA92uCW/9/haHa9U=
User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.1 (gnu/linux)
 by: Loris Bennett - Tue, 4 Apr 2023 11:58 UTC

Peter Otten <__peter__@web.de> writes:

> On 31/03/2023 15:01, Loris Bennett wrote:
[snip (53 lines)]

> Your problem has nothing to do with logging -- it's about visibility
> ("scope") of names:
>
>>>> def use_name():
> print(name)
>
>
>>>> def define_name():
> name = "Loris"
>
>
>>>> use_name()
> Traceback (most recent call last):
> File "<pyshell#56>", line 1, in <module>
> use_name()
> File "<pyshell#52>", line 2, in use_name
> print(name)
> NameError: name 'name' is not defined
>
> Binding (=assigning to) a name inside a function makes it local to that
> function. If you want a global (module-level) name you have to say so:
>
>>>> def define_name():
> global name
> name = "Peter"
>
>
>>>> define_name()
>>>> use_name()
> Peter

Thanks for the example and reminding me about Python's scopes.

With

global name

def use_name():
print(name)

def define_name():
name = "Peter"

define_name()
use_name()

I was initially surprised by the following error:

~/tmp $ python3 global.py
Traceback (most recent call last):
File "/home/loris/tmp/global.py", line 10, in <module>
use_name()
File "/home/loris/tmp/global.py", line 4, in use_name
print(name)
NameError: name 'name' is not defined

but I was misinterpreting

global name

to mean

define a global variable 'name'

whereas it actually seems to mean more like

use the global variable 'name'

Correct?

--
This signature is currently under constuction.

Re: When is logging.getLogger(__name__) needed?

<87sfde7b1s.fsf@hornfels.zedat.fu-berlin.de>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=22818&group=comp.lang.python#22818

  copy link   Newsgroups: comp.lang.python
Path: i2pn2.org!i2pn.org!news.swapon.de!fu-berlin.de!uni-berlin.de!not-for-mail
From: loris.be...@fu-berlin.de (Loris Bennett)
Newsgroups: comp.lang.python
Subject: Re: When is logging.getLogger(__name__) needed?
Date: Wed, 05 Apr 2023 14:45:03 +0200
Organization: ZEDAT, Freie Universität Berlin
Lines: 145
Message-ID: <87sfde7b1s.fsf@hornfels.zedat.fu-berlin.de>
References: <877cux2hy0.fsf@hornfels.zedat.fu-berlin.de>
<dd184814-69cb-3ce7-57f2-8e22eb8a02cf@DancesWithMice.info>
<mailman.2483.1680301344.20444.python-list@python.org>
Mime-Version: 1.0
Content-Type: text/plain
X-Trace: news.uni-berlin.de 5LFIA/E0dF8ufrqhgIhosQZ6dysYpxY/pqrH2IuioT4U1g
Cancel-Lock: sha1:L6/zvQHjbD3ltWqfYhOTD82UDHw=
User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.1 (gnu/linux)
 by: Loris Bennett - Wed, 5 Apr 2023 12:45 UTC

dn <PythonList@DancesWithMice.info> writes:

> On 01/04/2023 02.01, Loris Bennett wrote:
>> Hi,
>> In my top level program file, main.py, I have
>> def main_function():
>> parser = argparse.ArgumentParser(description="my prog")
>> ...
>> args = parser.parse_args()
>> config = configparser.ConfigParser()
>> if args.config_file is None:
>> config_file = DEFAULT_CONFIG_FILE
>> else:
>> config_file = args.config_file
>> config.read(config_file)
>> logging.config.fileConfig(fname=config_file)
>> logger = logging.getLogger(__name__)
>> do_some_stuff()
>> my_class_instance = myprog.MyClass()
>> def do_some_stuff():
>> logger.info("Doing stuff")
>> This does not work, because 'logger' is not known in the function
>> 'do_some_stuff'.
>> However, if in 'my_prog/my_class.py' I have
>> class MyClass:
>> def __init__(self):
>> logger.debug("created instance of MyClass")
>> this 'just works'.
>> I can add
>> logger = logging.getLogger(__name__)
>> to 'do_some_stuff', but why is this necessary in this case but not
>> in
>> the class?
>> Or should I be doing this entirely differently?
>
> Yes: differently.
>
> To complement @Peter's response, two items for consideration:
>
> 1 once main_function() has completed, have it return logger and other
> such values/constructs. The target-identifiers on the LHS of the
> function-call will thus be within the global scope.
>
> 2 if the purposes of main_function() are condensed-down to a few
> (English, or ..., language) phrases, the word "and" will feature, eg
> - configure env according to cmdLN args,
> - establish log(s),
> - do_some_stuff(), ** AND **
> - instantiate MyClass.
>
> If these (and do_some_stuff(), like MyClass' methods) were split into
> separate functions* might you find it easier to see them as separate
> sub-solutions? Each sub-solution would be able to contribute to the
> whole - the earlier ones as creating (outputting) a description,
> constraint, or basis; which becomes input to a later function/method.

So if I want to modify the logging via the command line I might have the
following:

---------------------------------------------------------------------

#!/usr/bin/env python3

import argparse
import logging

def get_logger(log_level):
"""Get global logger"""

logger = logging.getLogger('example')
logger.setLevel(log_level)
ch = logging.StreamHandler()
formatter = logging.Formatter('%(levelname)s - %(message)s')
ch.setFormatter(formatter)
logger.addHandler(ch)

return logger

def do_stuff():
"""Do some stuff"""

# logger.info("Doing stuff!")

def main():
"""Main"""

parser = argparse.ArgumentParser()
parser.add_argument("--log-level", dest="log_level", type=int)
args = parser.parse_args()

print(f"log level: {args.log_level}")

logger = get_logger(args.log_level)
logger.debug("Logger!")
do_stuff()

if __name__ == "__main__":
main()

---------------------------------------------------------------------

How can I get logging for 'do_stuff' in this case without explicitly
passing 'logger' as an argument or using 'global'?

Somehow I am failing to understand how to get 'logger' defined
sufficiently high up in the program that all references 'lower down' in
the program will be automatically resolved.

> * there is some debate amongst developers about whether "one function,
> one purpose" should be a rule, a convention, or tossed in the
> trash. YMMV!
>
> Personal view: SOLID's "Single" principle applies: there should be
> only one reason (hanging over the head of each method/function, like
> the Sword of Damocles) for it to change - or one 'user' who could
> demand a change to that function. In other words, an updated cmdLN
> option shouldn't affect a function which establishes logging, for
> example.
>
>
> Web.Refs:
> https://people.engr.tamu.edu/choe/choe/courses/20fall/315/lectures/slide23-solid.pdf
> https://www.hanselminutes.com/145/solid-principles-with-uncle-bob-robert-c-martin
> https://idioms.thefreedictionary.com/sword+of+Damocles
> https://en.wikipedia.org/wiki/Damocles

I don't really get the "one reason" idea and the Sword of Damocles
analogy. The later to me is more like "there's always a downside",
since the perks of being king may mean someone might try to usurp the
throne and kill you. Where is the "single principle" aspect?

However, the idea of "one responsibility" in the sense of "do only one
thing" seems relatively clear, especially if I think in terms of writing
unit tests.

Cheers,

Loris

--
This signature is currently under constuction.

Re: When is logging.getLogger(__name__) needed?

<87o7o27a29.fsf@hornfels.zedat.fu-berlin.de>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=22819&group=comp.lang.python#22819

  copy link   Newsgroups: comp.lang.python
Path: i2pn2.org!i2pn.org!news.swapon.de!fu-berlin.de!uni-berlin.de!not-for-mail
From: loris.be...@fu-berlin.de (Loris Bennett)
Newsgroups: comp.lang.python
Subject: Re: When is logging.getLogger(__name__) needed?
Date: Wed, 05 Apr 2023 15:06:22 +0200
Organization: ZEDAT, Freie Universität Berlin
Lines: 152
Message-ID: <87o7o27a29.fsf@hornfels.zedat.fu-berlin.de>
References: <877cux2hy0.fsf@hornfels.zedat.fu-berlin.de>
<dd184814-69cb-3ce7-57f2-8e22eb8a02cf@DancesWithMice.info>
<mailman.2483.1680301344.20444.python-list@python.org>
<87sfde7b1s.fsf@hornfels.zedat.fu-berlin.de>
Mime-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
X-Trace: news.uni-berlin.de VK1sfRDt0b8LYVO/5pCz5Am6e0OTmy7gJqn0d1fczt0lPc
Cancel-Lock: sha1:uKzSrf5aVbEmg+WK1vQFK4kd5cU=
User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.1 (gnu/linux)
 by: Loris Bennett - Wed, 5 Apr 2023 13:06 UTC

"Loris Bennett" <loris.bennett@fu-berlin.de> writes:

> dn <PythonList@DancesWithMice.info> writes:
>
>> On 01/04/2023 02.01, Loris Bennett wrote:
>>> Hi,
>>> In my top level program file, main.py, I have
>>> def main_function():
>>> parser = argparse.ArgumentParser(description="my prog")
>>> ...
>>> args = parser.parse_args()
>>> config = configparser.ConfigParser()
>>> if args.config_file is None:
>>> config_file = DEFAULT_CONFIG_FILE
>>> else:
>>> config_file = args.config_file
>>> config.read(config_file)
>>> logging.config.fileConfig(fname=config_file)
>>> logger = logging.getLogger(__name__)
>>> do_some_stuff()
>>> my_class_instance = myprog.MyClass()
>>> def do_some_stuff():
>>> logger.info("Doing stuff")
>>> This does not work, because 'logger' is not known in the function
>>> 'do_some_stuff'.
>>> However, if in 'my_prog/my_class.py' I have
>>> class MyClass:
>>> def __init__(self):
>>> logger.debug("created instance of MyClass")
>>> this 'just works'.
>>> I can add
>>> logger = logging.getLogger(__name__)
>>> to 'do_some_stuff', but why is this necessary in this case but not
>>> in
>>> the class?
>>> Or should I be doing this entirely differently?
>>
>> Yes: differently.
>>
>> To complement @Peter's response, two items for consideration:
>>
>> 1 once main_function() has completed, have it return logger and other
>> such values/constructs. The target-identifiers on the LHS of the
>> function-call will thus be within the global scope.
>>
>> 2 if the purposes of main_function() are condensed-down to a few
>> (English, or ..., language) phrases, the word "and" will feature, eg
>> - configure env according to cmdLN args,
>> - establish log(s),
>> - do_some_stuff(), ** AND **
>> - instantiate MyClass.
>>
>> If these (and do_some_stuff(), like MyClass' methods) were split into
>> separate functions* might you find it easier to see them as separate
>> sub-solutions? Each sub-solution would be able to contribute to the
>> whole - the earlier ones as creating (outputting) a description,
>> constraint, or basis; which becomes input to a later function/method.
>
> So if I want to modify the logging via the command line I might have the
> following:
>
> ---------------------------------------------------------------------
>
> #!/usr/bin/env python3
>
> import argparse
> import logging
>
>
> def get_logger(log_level):
> """Get global logger"""
>
> logger = logging.getLogger('example')
> logger.setLevel(log_level)
> ch = logging.StreamHandler()
> formatter = logging.Formatter('%(levelname)s - %(message)s')
> ch.setFormatter(formatter)
> logger.addHandler(ch)
>
> return logger
>
>
> def do_stuff():
> """Do some stuff"""
>
> # logger.info("Doing stuff!")

Looks like I just need

logger = logging.getLogger('example)
logger.info("Doing stuff!")

>
> def main():
> """Main"""
>
> parser = argparse.ArgumentParser()
> parser.add_argument("--log-level", dest="log_level", type=int)
> args = parser.parse_args()
>
> print(f"log level: {args.log_level}")
>
> logger = get_logger(args.log_level)
> logger.debug("Logger!")
> do_stuff()
>
>
> if __name__ == "__main__":
> main()
>
> ---------------------------------------------------------------------
>
> How can I get logging for 'do_stuff' in this case without explicitly
> passing 'logger' as an argument or using 'global'?
>
> Somehow I am failing to understand how to get 'logger' defined
> sufficiently high up in the program that all references 'lower down' in
> the program will be automatically resolved.
>
>> * there is some debate amongst developers about whether "one function,
>> one purpose" should be a rule, a convention, or tossed in the
>> trash. YMMV!
>>
>> Personal view: SOLID's "Single" principle applies: there should be
>> only one reason (hanging over the head of each method/function, like
>> the Sword of Damocles) for it to change - or one 'user' who could
>> demand a change to that function. In other words, an updated cmdLN
>> option shouldn't affect a function which establishes logging, for
>> example.
>>
>>
>> Web.Refs:
>> https://people.engr.tamu.edu/choe/choe/courses/20fall/315/lectures/slide23-solid.pdf
>> https://www.hanselminutes.com/145/solid-principles-with-uncle-bob-robert-c-martin
>> https://idioms.thefreedictionary.com/sword+of+Damocles
>> https://en.wikipedia.org/wiki/Damocles
>
> I don't really get the "one reason" idea and the Sword of Damocles
> analogy. The later to me is more like "there's always a downside",
> since the perks of being king may mean someone might try to usurp the
> throne and kill you. Where is the "single principle" aspect?
>
> However, the idea of "one responsibility" in the sense of "do only one
> thing" seems relatively clear, especially if I think in terms of writing
> unit tests.
>
> Cheers,
>
> Loris
--
Dr. Loris Bennett (Herr/Mr)
ZEDAT, Freie Universität Berlin

Re: When is logging.getLogger(__name__) needed?

<mailman.0.1680741208.20750.python-list@python.org>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=22821&group=comp.lang.python#22821

  copy link   Newsgroups: comp.lang.python
Path: i2pn2.org!i2pn.org!news.swapon.de!fu-berlin.de!uni-berlin.de!not-for-mail
From: PythonL...@DancesWithMice.info (dn)
Newsgroups: comp.lang.python
Subject: Re: When is logging.getLogger(__name__) needed?
Date: Thu, 6 Apr 2023 12:33:08 +1200
Organization: DWM
Lines: 328
Message-ID: <mailman.0.1680741208.20750.python-list@python.org>
References: <877cux2hy0.fsf@hornfels.zedat.fu-berlin.de>
<dd184814-69cb-3ce7-57f2-8e22eb8a02cf@DancesWithMice.info>
<mailman.2483.1680301344.20444.python-list@python.org>
<87sfde7b1s.fsf@hornfels.zedat.fu-berlin.de>
<87o7o27a29.fsf@hornfels.zedat.fu-berlin.de>
<34d45701-291d-3f08-2536-38b63b523b47@DancesWithMice.info>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
X-Trace: news.uni-berlin.de Cc2P1yY6xRROyDnUNHFIaQHIO9+IVBlVJFnt/kEC1KMw==
Return-Path: <PythonList@DancesWithMice.info>
X-Original-To: python-list@python.org
Delivered-To: python-list@mail.python.org
Authentication-Results: mail.python.org; dkim=pass
reason="2048-bit key; unprotected key"
header.d=danceswithmice.info header.i=@danceswithmice.info
header.b=aXFOvpSo; dkim-adsp=pass; dkim-atps=neutral
X-Spam-Status: OK 0.000
X-Spam-Evidence: '*H*': 1.00; '*S*': 0.00; 'looks': 0.02; 'argument':
0.04; 'def': 0.04; '(for': 0.05; 'despite': 0.05; 'frequent':
0.05; 'random': 0.05; 'settings.': 0.05; 'explicitly': 0.07;
'influence': 0.07; 'sprints': 0.07; 'tests': 0.07; 'url:courses':
0.07; 'wanting': 0.07; "'''": 0.09; '=dn': 0.09; 'describe': 0.09;
'else:': 0.09; 'example.': 0.09; 'excludes': 0.09;
'from:addr:danceswithmice.info': 0.09; 'from:addr:pythonlist':
0.09; 'like,': 0.09; "shouldn't": 0.09; 'smaller': 0.09;
'subject:needed': 0.09; 'treated': 0.09; 'web.': 0.09; 'writes:':
0.09; 'tutorial': 0.12; 'coding': 0.13; 'import': 0.15; '...,':
0.16; '.py': 0.16; '>>>>': 0.16; 'achieves': 0.16; 'another.':
0.16; 'applies:': 0.16; 'arguments': 0.16; 'author,': 0.16;
'bennett': 0.16; 'better!': 0.16; 'constraint,': 0.16;
'convention,': 0.16; 'demonstrates': 0.16; 'duplication': 0.16;
'executed': 0.16; 'fourth': 0.16; 'instance': 0.16; 'main()':
0.16; 'message-id:@DancesWithMice.info': 0.16; 'none:': 0.16;
'omission': 0.16; 'python")': 0.16; 'python3': 0.16;
'received:51.254': 0.16; 'received:51.254.211': 0.16;
'received:51.254.211.219': 0.16; 'received:cloud': 0.16;
'received:rangi.cloud': 0.16; 'relatively': 0.16; 'risk.': 0.16;
'script,': 0.16; 'script.': 0.16; 'separately': 0.16;
'something.': 0.16; 'somewhat': 0.16; 'statements.': 0.16;
'successful.': 0.16; 'tdd': 0.16; 'unlikely': 0.16; 'url:howto':
0.16; 'whichever': 0.16; 'wrote:': 0.16; 'to:addr:python-list':
0.20; 'option': 0.20; 'input': 0.21; 'unable': 0.21; 'written':
0.22; 'languages': 0.22; 'integration': 0.22; 'purposes': 0.22;
'skip:_ 10': 0.22; 'code': 0.23; 'command': 0.23; 'skip:p 30':
0.23; 'url:wiki': 0.23; 'run': 0.23; 'idea': 0.24; '(and': 0.25;
'python,': 0.25; 'seems': 0.26; 'classes': 0.26; 'configure':
0.26; 'creating': 0.27; 'else': 0.27; 'function': 0.27; 'done':
0.28; '>>>': 0.28; 'etc': 0.28; 'expect': 0.28; 'purpose': 0.28;
'sense': 0.28; 'global': 0.73; 'little': 0.73; 'head': 0.73;
'easy': 0.74; 'demand': 0.75; 'change,': 0.76; 'choice': 0.76;
'degree': 0.76; 'url-ip:209/8': 0.76; 'life': 0.77; 'business':
0.77; 'discuss': 0.78; 'highly': 0.78; 'established': 0.80;
'quickly': 0.80; 'unit': 0.81; 'known': 0.84; 'need.': 0.84;
'activity.': 0.84; 'apparent': 0.84; 'burst': 0.84; 'complement':
0.84; 'conveys': 0.84; 'danger': 0.84; 'debate': 0.84;
'digitalocean': 0.84; 'establishes': 0.84; 'feature,': 0.84;
'further,': 0.84; 'implies': 0.84; 'legislation': 0.84;
'license,': 0.84; 'merely': 0.84; 'organised': 0.84; 'perks':
0.84; 'rare': 0.84; 'reduces': 0.84; 'sufficiently': 0.84;
'thus,': 0.84; 'url-ip:104.16.181/24': 0.84; 'url:people': 0.84;
'well),': 0.84; '"do': 0.91; 'affect': 0.91; 'largely': 0.91;
'tend': 0.91; 'dream': 0.93
DKIM-Filter: OpenDKIM Filter v2.11.0 vps.rangi.cloud E1B2F8522
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=danceswithmice.info;
s=staff; t=1680741199;
bh=5aOWjyAHz/z9HA30K5fhHdRyq0P6GpBF39RILyGgK7U=;
h=Date:Subject:To:References:From:In-Reply-To:From;
b=aXFOvpSo9CRKh+wTK+yv3xUbIM2sYsDA9QsaTple1uZVopjHfy68v9ea1aTWSi++f
HtC0gxMV+F+YhxKRdNFvhBlWyRQejlGSgtWQ/ITxWp6Fx1j1BkzF1l8UCvpDgwUOJM
LLIzULwEZMeakIquwW5lUJRwI/Y8bxFDv8KACBBKTD7sTRVtPDnudxCbxu5YQV4tVG
8dZ3qdFSjZc9Wfo4aP494dGT5xlu33yTV6cRlGFNVfkfCiYl+Kd5/1XfGfaKOKP0u3
AhRBPg/NQHK40xI/xRHJ+CYZfUJLMfP71PUktLImhLfZaqrJV/RGm3ldNSuE64Zj1U
aeabpxvnkzEQA==
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
Thunderbird/102.9.1
Content-Language: en-GB
In-Reply-To: <87o7o27a29.fsf@hornfels.zedat.fu-berlin.de>
X-BeenThere: python-list@python.org
X-Mailman-Version: 2.1.39
Precedence: list
List-Id: General discussion list for the Python programming language
<python-list.python.org>
List-Unsubscribe: <https://mail.python.org/mailman/options/python-list>,
<mailto:python-list-request@python.org?subject=unsubscribe>
List-Archive: <https://mail.python.org/pipermail/python-list/>
List-Post: <mailto:python-list@python.org>
List-Help: <mailto:python-list-request@python.org?subject=help>
List-Subscribe: <https://mail.python.org/mailman/listinfo/python-list>,
<mailto:python-list-request@python.org?subject=subscribe>
X-Mailman-Original-Message-ID: <34d45701-291d-3f08-2536-38b63b523b47@DancesWithMice.info>
X-Mailman-Original-References: <877cux2hy0.fsf@hornfels.zedat.fu-berlin.de>
<dd184814-69cb-3ce7-57f2-8e22eb8a02cf@DancesWithMice.info>
<mailman.2483.1680301344.20444.python-list@python.org>
<87sfde7b1s.fsf@hornfels.zedat.fu-berlin.de>
<87o7o27a29.fsf@hornfels.zedat.fu-berlin.de>
 by: dn - Thu, 6 Apr 2023 00:33 UTC

Thank you for carefully considering suggestions (and implications) - and
which will 'work' for you.

Further comment below (and with apologies that, unusually for me, there
are many personal opinions mixed-in):-

On 06/04/2023 01.06, Loris Bennett wrote:
> "Loris Bennett" <loris.bennett@fu-berlin.de> writes:
>> dn <PythonList@DancesWithMice.info> writes:
>>> On 01/04/2023 02.01, Loris Bennett wrote:
>>>> Hi,
>>>> In my top level program file, main.py, I have
>>>> def main_function():
>>>> parser = argparse.ArgumentParser(description="my prog")
>>>> ...
>>>> args = parser.parse_args()
>>>> config = configparser.ConfigParser()
>>>> if args.config_file is None:
>>>> config_file = DEFAULT_CONFIG_FILE
>>>> else:
>>>> config_file = args.config_file
>>>> config.read(config_file)
>>>> logging.config.fileConfig(fname=config_file)
>>>> logger = logging.getLogger(__name__)
>>>> do_some_stuff()
>>>> my_class_instance = myprog.MyClass()
>>>> def do_some_stuff():
>>>> logger.info("Doing stuff")
>>>> This does not work, because 'logger' is not known in the function
>>>> 'do_some_stuff'.
>>>> However, if in 'my_prog/my_class.py' I have
>>>> class MyClass:
>>>> def __init__(self):
>>>> logger.debug("created instance of MyClass")
>>>> this 'just works'.
>>>> I can add
>>>> logger = logging.getLogger(__name__)
>>>> to 'do_some_stuff', but why is this necessary in this case but not
>>>> in
>>>> the class?
>>>> Or should I be doing this entirely differently?
>>>
>>> Yes: differently.
>>>
>>> To complement @Peter's response, two items for consideration:
>>>
>>> 1 once main_function() has completed, have it return logger and other
>>> such values/constructs. The target-identifiers on the LHS of the
>>> function-call will thus be within the global scope.
>>>
>>> 2 if the purposes of main_function() are condensed-down to a few
>>> (English, or ..., language) phrases, the word "and" will feature, eg
>>> - configure env according to cmdLN args,
>>> - establish log(s),
>>> - do_some_stuff(), ** AND **
>>> - instantiate MyClass.
>>>
>>> If these (and do_some_stuff(), like MyClass' methods) were split into
>>> separate functions* might you find it easier to see them as separate
>>> sub-solutions? Each sub-solution would be able to contribute to the
>>> whole - the earlier ones as creating (outputting) a description,
>>> constraint, or basis; which becomes input to a later function/method.
>>
>> So if I want to modify the logging via the command line I might have the
>> following:
>>
>> ---------------------------------------------------------------------
>>
>> #!/usr/bin/env python3
>>
>> import argparse
>> import logging
>>
>>
>> def get_logger(log_level):
>> """Get global logger"""
>>
>> logger = logging.getLogger('example')
>> logger.setLevel(log_level)
>> ch = logging.StreamHandler()
>> formatter = logging.Formatter('%(levelname)s - %(message)s')
>> ch.setFormatter(formatter)
>> logger.addHandler(ch)
>>
>> return logger
>>
>>
>> def do_stuff():
>> """Do some stuff"""
>>
>> # logger.info("Doing stuff!")
>
> Looks like I just need
>
> logger = logging.getLogger('example)
> logger.info("Doing stuff!")
>
>>
>> def main():
>> """Main"""
>>
>> parser = argparse.ArgumentParser()
>> parser.add_argument("--log-level", dest="log_level", type=int)
>> args = parser.parse_args()
>>
>> print(f"log level: {args.log_level}")
>>
>> logger = get_logger(args.log_level)
>> logger.debug("Logger!")
>> do_stuff()
>>
>>
>> if __name__ == "__main__":
>> main()
>>
>> ---------------------------------------------------------------------
>>
>> How can I get logging for 'do_stuff' in this case without explicitly
>> passing 'logger' as an argument or using 'global'?
>>
>> Somehow I am failing to understand how to get 'logger' defined
>> sufficiently high up in the program that all references 'lower down' in
>> the program will be automatically resolved.

At the risk of 'heresy', IMHO the idea of main() is (almost always)
unnecessary in Python, and largely a habit carried-over from other
languages (need for an entry-/end-point).

NB be sure of the difference between a "script" and a "module"...

My script template-overview:

''' Script docstring. '''
- author, license, etc docs

global constants such as import-s
set environment

if __name__ == "__main__":
do_this()
do_that()
ie the business of the script

Despite its frequent use, I'm somewhat amused by the apparent
duplication within:

if __name__ == "__main__":
main()

ie if this .py file is being executed as a script, call main() - where
main() is the purpose of the script. Whereas if the file is an import-ed
module, do not execute any of the contained-code.

Thus, the if-statement achieves the same separation as the main()
function encapsulation. Also, the word main() conveys considerably less
meaning than (say) establish_logging().

NB others may care to offer alternate advice for your consideration...

There is a good argument for main(), in that it might enable tests to be
written which assure the integration of several tasks called by the
script. Plus, if one excludes non-TDD test-able code, such as user
interfaces, even 'fancy headings' and printing of conclusions; there's
little left. Accordingly, I don't mind the apparent duplication involved
in coding an integration test which checks that do_this() and do_that()
are playing-nicely together. YMMV!

I'm not sure why, but my 'mainlines' never seem to be very long. Once I
had been introduced to "Modular Programming" (1970s?), it seemed that
the purpose of a mainline was merely calling one do-it function after
another.

To me mainline's seem highly unlikely to be re-usable. Thus, the
possibility that main() might need to be import-able to some other
script, is beyond my experience/recollection.

Further, my .py file scripts/mainlines tend to be short and often don't
contain any of the functions or classes which actually do-the-work - all
are import-ed (and thus, they are easier to re-use!?)

Returning to 'set environment': the code-examples include argparse and
logger. Both (in my thinking) are part of creating the environment in
which the code will execute.

Logging for example, is the only choice when we need to be aware of how
a web-based system is running (or running into problems) - otherwise, as
some would argue, we might as well use print(). Similarly, argparse will
often influence the way a script executes, the data it should use, etc.

Much of such forms the (global) environment in which (this run of) the
code will execute. Hence locating such setting of priorities and
constraints, adjacent to the import statements.

These must be established before getting on with 'the business'. That
said, if someone prefers to put it under if __main__, I won't burst into
tears. (see earlier comment about the .py file as a script cf module)

You have answered your own question about logging. Well done!

The logging instance can either be explicitly passed into each
(relevant) function, or it can be treated as a global and thus available
implicitly. (see also: "Zen of Python")

I prefer your approach of get_logger() - even if that name doesn't quite
describe the establishment of a logger and its settings. All of that
part of setting the environment is collected into one place. Which
in-turn, makes it easy to work on any changes, or work-in any parameters
which may come from other environment-setting activity.


Click here to read the complete article
1
server_pubkey.txt

rocksolid light 0.9.81
clearnet tor