[Mailman-Developers] Unclear usage of `member = ISubscriptionManager(mlist).register(…)`

2022-02-25 Thread Stephen J. Turnbull
I hope I'm not underestimating your understanding.  If so, no offense
intended.  I don't think Mark's answer entirely addressed your
question, so here goes.

Дилян Палаузов writes:

 > I am trying to understand the source code.  My reading is, that
 > interfaces/subscriptions.py:class ISubscriptionManager.register always
 > returns a 3-tuple and the last element of the tuple is a member object,
 > or None.   This coincides with the implementation in
 > app/subscriptions.py.SubscriptionManager.register .
 > cli_synmembers.py:add_members() contains:
 > 
 > member = [...]
[...]
 > and commands/cli_addmembers.py:add_members() contains
 > 
 > member = [...]

 > So my question is: when regirstar.register returns a tuple, the last
 > argument of which is a members,

It's not a members (plural).  The last element is a member
(singular), as the code accessing it indicates.

 > why do the above snippets store the
 > result in a variable called `member`?

If you look a little bit earlier in cli_addmembers.py:add_members
(this one is plural!), you see

for line in in_fp:
# line parsing stuff and then
try:
member = [...]# the line quoted from your message above

What is in_fp?  It's a file object returned from open().  The
structure of that file is a sequence of lines, where each line
contains either a display name and an address enclosed in <>, or an
address, to be tested for membership, and if not a member to be
registered (both of those are encapsulated in registrar.register, the
result of the test is communicated by raising AlreadySubscribedError
or not).

So cli_addmembers is able to handle more than one subscription at a
time, but it passes them to register one at a time.  That's why the
function's name is plural, but the local variable name is singular.

 > How are the set preferences set to member handled further, as my
 > reading is that the variable just disappears, immediately after
 > member.preferences is set?

The one-line answer is "it's SQLAlchemy 'magic'." :-)

Note the decorator "@transactional* at the top.  That says that this
function manipulates the external database in sqlite3, postgresql, or
mysql, and if it fails in any way, all of it should be rolled back and
not entered into the database.  How this connection to a RDBMS works
is too complicated to explain it detail here, but the basic idea is
that the member object returned from registrar.register is endowed
with properties that call SQLAlchemy to add or update the member
records in the external database.  This makes it possible for you, the
programmer, to manipulate objects like member as ordinary Python
objects, but changes you make to them are reflected persistently in a
database.

OK, a little more detail since you'd need to study SQLAlchemy:
basically what an object-relational manager like SQLAlchemy does is to
provide code that accesses and caches data from the RDMBS when an
object's attributes are accessed, and more code that issues database
updates when they are changed.  @transactional wraps the function it
decorates in code that first creates an RDMBS transaction, then calls
the function.  This means that the database code does not update the
external database immediately, but queues the updates in the
transaction.  Finally, if the function exits normally, @transactional
regains control and executes the transaction, making all updates to
the database.

All this means that classes defined in a model/*.py have instances
that can be treated as persisting even after the program exits.  This
is actually quite natural if you consider how Python variables are not
variables in the sense of a data container in memory, but just name-
object bindings.

___
Mailman-Developers mailing list -- mailman-developers@python.org
To unsubscribe send an email to mailman-developers-le...@python.org
https://mail.python.org/mailman3/lists/mailman-developers.python.org/
Mailman FAQ: https://wiki.list.org/x/AgA3

Security Policy: https://wiki.list.org/x/QIA9


[Mailman-Developers] Re: Unclear usage of `member = ISubscriptionManager(mlist).register(…)`

2022-02-25 Thread Mark Sapiro

On 2/25/22 12:16, Дилян Палаузов wrote:

Hello,

I am trying to understand the source code.  My reading is, that
interfaces/subscriptions.py:class ISubscriptionManager.register always
returns a 3-tuple and the last element of the tuple is a member object,
or None.   This coincides with the implementation in
app/subscriptions.py.SubscriptionManager.register .
cli_synmembers.py:add_members() contains:

 member = registrar.register(
 subscriber,
 pre_verified=True,
 pre_approved=True,
 pre_confirmed=True,
 send_welcome_message=welcome_msg)[2]
 member.preferences.delivery_status = delivery_status
 member.preferences.delivery_mode = delivery_mode
 return

and commands/cli_addmembers.py:add_members() contains

 member = registrar.register(
 subscriber,
 pre_verified=True,
 pre_approved=True,
 pre_confirmed=True,
 invitation=invite,
 send_welcome_message=welcome_msg)[2]
 if member is not None:
 member.preferences.delivery_status = delivery_status
 member.preferences.delivery_mode = delivery_mode
 return

So my question is: when regirstar.register returns a tuple, the last
argument of which is a members, why do the above snippets store the
result in a variable called `member`?



The above snippets say  member = registrar.register(...)[2]

I.e. member is set to the last element of the 3-tuple.


--
Mark Sapiro The highway is for gamblers,
San Francisco Bay Area, Californiabetter use your sense - B. Dylan
___
Mailman-Developers mailing list -- mailman-developers@python.org
To unsubscribe send an email to mailman-developers-le...@python.org
https://mail.python.org/mailman3/lists/mailman-developers.python.org/
Mailman FAQ: https://wiki.list.org/x/AgA3

Security Policy: https://wiki.list.org/x/QIA9


[Mailman-Developers] Unclear usage of `member = ISubscriptionManager(mlist).register(…)`

2022-02-25 Thread Дилян Палаузов
Hello,

I am trying to understand the source code.  My reading is, that
interfaces/subscriptions.py:class ISubscriptionManager.register always
returns a 3-tuple and the last element of the tuple is a member object,
or None.   This coincides with the implementation in
app/subscriptions.py.SubscriptionManager.register .
cli_synmembers.py:add_members() contains:

member = registrar.register(
subscriber,
pre_verified=True,
pre_approved=True,
pre_confirmed=True,
send_welcome_message=welcome_msg)[2]
member.preferences.delivery_status = delivery_status
member.preferences.delivery_mode = delivery_mode
return

and commands/cli_addmembers.py:add_members() contains

member = registrar.register(
subscriber,
pre_verified=True,
pre_approved=True,
pre_confirmed=True,
invitation=invite,
send_welcome_message=welcome_msg)[2]
if member is not None:
member.preferences.delivery_status = delivery_status
member.preferences.delivery_mode = delivery_mode
return

So my question is: when regirstar.register returns a tuple, the last
argument of which is a members, why do the above snippets store the
result in a variable called `member`?

How are the set preferences set to member handled further, as my
reading is that the variable just disappears, immediately after
member.preferences is set?

Greeting
  Дилян
___
Mailman-Developers mailing list -- mailman-developers@python.org
To unsubscribe send an email to mailman-developers-le...@python.org
https://mail.python.org/mailman3/lists/mailman-developers.python.org/
Mailman FAQ: https://wiki.list.org/x/AgA3

Security Policy: https://wiki.list.org/x/QIA9