Re: Getty fully qualified class name from class object

2023-08-23 Thread Ian Pilcher via Python-list

On 8/22/23 11:13, Greg Ewing via Python-list wrote:

Classes have a __module__ attribute:

 >>> logging.Handler.__module__
'logging'


Not sure why I didn't think to look for such a thing.  Looks like it's
as simple as f'{cls.__module__}.{cls.__qualname__}'.

Thanks!

--

Google  Where SkyNet meets Idiocracy


--
https://mail.python.org/mailman/listinfo/python-list


Getty fully qualified class name from class object

2023-08-22 Thread Ian Pilcher via Python-list

How can I programmatically get the fully qualified name of a class from
its class object?  (I'm referring to the name that is shown when str()
or repr() is called on the class object.)

Neither the __name__ or __qualname__ class attributes include the
module.  For example:

  >>> import logging

  >>> str(logging.Handler)
  ""

  >>> logging.Handler.__name__
  'Handler'
  >>> logging.Handler.__qualname__
  'Handler'

How can I programmatically get 'logging.Handler' from the class object?

--

Google  Where SkyNet meets Idiocracy

--
https://mail.python.org/mailman/listinfo/python-list


Which more Pythonic - self.__class__ or type(self)?

2023-03-02 Thread Ian Pilcher

Seems like an FAQ, and I've found a few things on StackOverflow that
discuss the technical differences in edge cases, but I haven't found
anything that talks about which form is considered to be more Pythonic
in those situations where there's no functional difference.

Is there any consensus?

--

Google  Where SkyNet meets Idiocracy

--
https://mail.python.org/mailman/listinfo/python-list


Re: Tool that can document private inner class?

2023-02-08 Thread Ian Pilcher

On 2/8/23 08:25, Weatherby,Gerard wrote:

No.

I interpreted your query as “is there something that can read docstrings 
of dunder methods?”


Have you tried the Sphinx specific support forums? 
https://www.sphinx-doc.org/en/master/support.html 


Yes.  I've posted to both the -user and -dev groups, and I've also filed
an issue[1].  I haven't received a response.

Thus my conclusion that Sphinx, specifically autodoc, simply can't do
this.

[1] https://github.com/sphinx-doc/sphinx/issues/11181

--

Google  Where SkyNet meets Idiocracy


--
https://mail.python.org/mailman/listinfo/python-list


Re: Tool that can document private inner class?

2023-02-07 Thread Ian Pilcher

On 2/7/23 14:53, Weatherby,Gerard wrote:

Yes.

Inspect module

import inspect


class Mine:

def __init__(self):
self.__value = 7

def __getvalue(self):
/"""Gets seven"""
/return self.__value


mine = Mine()
data = inspect.getdoc(mine)
for m in inspect.getmembers(mine):
if '__getvalue' in m[0]:
     d = inspect.getdoc(m[1])
print(d)



Can inspect generate HTML documentation, à la Sphinx and other tools?

--

Google  Where SkyNet meets Idiocracy


--
https://mail.python.org/mailman/listinfo/python-list


Tool that can document private inner class?

2023-02-07 Thread Ian Pilcher

I've been banging my head on Sphinx for a couple of days now, trying to
get it to include the docstrings of a private (name starts with two
underscores) inner class.  All I've managed to do is convince myself
that it really can't do it.

See https://github.com/sphinx-doc/sphinx/issues/11181.

Is there a tool out there that can do this?

--

Google  Where SkyNet meets Idiocracy

--
https://mail.python.org/mailman/listinfo/python-list


Re: set.add() doesn't replace equal element

2022-12-31 Thread Ian Pilcher

On 12/30/22 17:00, Paul Bryan wrote:
It seems to me like you have to ideas of what "equal" means. You want to 
update a "non-equal/equal" value in the set (because of a different time 
stamp). If you truly considered them equal, the time stamp would be 
irrelevant and updating the value in the set would be unnecessary.


I would:

a) /not/ consider two different leases with two different time stamps to 
be equal, and
b) as already mentioned, store them in another data structure like a 
dictionary.


Not knowing the specifics of the DHCP object structure, if a DHCP lease 
object has some immutable key or other durable immutable attribute, I 
would be inclined to make that the dictionary key, and store the DHCP 
object as the value.


I have come to the conclusion that you are correct.  Thanks!

--

Google  Where SkyNet meets Idiocracy


--
https://mail.python.org/mailman/listinfo/python-list


Re: set.add() doesn't replace equal element

2022-12-30 Thread Ian Pilcher

On 12/30/22 15:47, Paul Bryan wrote:
What kind of elements are being added to the set? Can you show 
reproducible sample code?


The objects in question are DHCP leases.  I consider them "equal" if
the lease address (or IPv6 prefix) is equal, even if the timestamps have
changed.  That code is not small, but it's easy to demonstrate the
behavior.

>>> import datetime
>>> class Foo(object):
... def __init__(self, index):
... self.index = index
... self.timestamp = datetime.datetime.now()
... def __eq__(self, other):
... return type(other) is Foo and other.index == self.index
... def __hash__(self):
... return hash(self.index)
... def __repr__(self):
... return f'Foo({self.index}) created at {str(self.timestamp)}'
...
>>> f1 = Foo(1)
>>> s = { f1 }
>>> s
{Foo(1) created at 2022-12-30 16:24:12.352908}
>>> f2 = Foo(1)
>>> f2
Foo(1) created at 2022-12-30 16:24:35.489208
>>> s.add(f2)
>>> s
{Foo(1) created at 2022-12-30 16:24:12.352908}

--

Google  Where SkyNet meets Idiocracy


--
https://mail.python.org/mailman/listinfo/python-list


set.add() doesn't replace equal element

2022-12-30 Thread Ian Pilcher

I just discovered this behavior, which is problematic for my particular
use.  Is there a different set API (or operator) that can be used to
add an element to a set, and replace any equal element?

If not, am I correct that I should call set.discard() before calling
set.add() to achieve the behavior that I want?

--

Google  Where SkyNet meets Idiocracy

--
https://mail.python.org/mailman/listinfo/python-list


Re: Calling pselect/ppoll/epoll_pwait

2022-12-13 Thread Ian Pilcher

On 12/2/22 14:00, Ian Pilcher wrote:

Does Python provide any way to call the "p" variants of the I/O
multiplexing functions?


Just to close this out ...

As others suggested, there's no easy way to call the "p" variants of the
I/O multiplexing functions, but this can be worked around by "mapping"
signals to file descriptors.

There are a few ways to accomplish this.

1. Use a Linux signalfd.  There's at least one library out there that
   provides signalfd support to Python.

2. Use signal.set_wakeup_fd()[1].  I didn't really explore this, as it
   appears that there isn't any way to filter the signals that will be
   reported.

3. Roll your own.  This turned out to be really simple for my use case,
   which is simply to set an exit flag and wake my program up if it
   receives SIGINT or SIGTERM.

   _sel = selectors.DefaultSelector()
   _exit_flag = False
   _sig_pipe_r, _sig_pipe_w = os.pipe2(os.O_NONBLOCK | os.O_CLOEXEC)

   def _sig_handler(signum, frame):
   global _exit_flag
   _exit_flag = True
   os.write(_sig_pipe_w, b'\x00')

   _sel.register(_sig_pipe_r, selectors.EVENT_READ)
   # register other file descriptors of interest
   signal.signal(signal.SIGINT, _sig_handler)
   signal.signal(signal.SIGTERM, _sig_handler)
   while not _exit_flag:
   ready = _sel.select()
   # handle other file descriptors

[1] https://docs.python.org/3/library/signal.html#signal.set_wakeup_fd

--

Google  Where SkyNet meets Idiocracy


--
https://mail.python.org/mailman/listinfo/python-list


Calling pselect/ppoll/epoll_pwait

2022-12-02 Thread Ian Pilcher

Does Python provide any way to call the "p" variants of the I/O
multiplexing functions?

Looking at the documentation of the select[1] and selectors[2] modules,
it appears that they expose only the "non-p" variants.

[1] https://docs.python.org/3/library/select.html
[2] https://docs.python.org/3/library/selectors.html

--

Google  Where SkyNet meets Idiocracy

--
https://mail.python.org/mailman/listinfo/python-list


Re: Dealing with non-callable classmethod objects

2022-11-12 Thread Ian Pilcher

On 11/12/22 14:57, Cameron Simpson wrote:
You shouldn't need a throwaway class, just use the name "classmethod" 
directly - it's the type!


     if not callable(factory):
     if type(factory) is classmethod:
     # replace fctory with a function calling factory.__func__
     factory = lambda arg: factory.__func__(classmethod, arg)
     else:
     raise TypeError("unhandled factory type %s:%r" % 
(type(factory), factory)

     value = factory(d[attr])


Or I could use the C++ version:

  face << palm;

Thanks!

--

Google  Where SkyNet meets Idiocracy


--
https://mail.python.org/mailman/listinfo/python-list


Re: Dealing with non-callable classmethod objects

2022-11-12 Thread Ian Pilcher

On 11/11/22 16:47, Cameron Simpson wrote:

On 11Nov2022 15:29, Ian Pilcher  wrote:

* Can I improve the 'if callable(factory):' test above?  This treats
 all non-callable objects as classmethods, which is obviously not
 correct.  Ideally, I would check specifically for a classmethod, but
 there doesn't seem to be any literal against which I could check the
 factory's type.


Yeah, it does feel a bit touchy feely.

You could see if the `inspect` module tells you more precise things 
about the `factory`.


The other suggestion I have is to put the method name in `_attrs`; if 
that's a `str` you could special case it as a well known type for the 
factory and look it up with `getattr(cls,factory)`.


So I've done this.

class _HasUnboundClassMethod(object):
@classmethod
def _classmethod(cls):
pass  # pragma: no cover
_methods = [ _classmethod ]

_ClassMethodType = type(_HasUnboundClassMethod._methods[0])

Which allows me to do this:

def __init__(self, d):
for attr, factory in self._attrs.items():
if callable(factory):
value = factory(d[attr])
else:
assert type(factory) is self._ClassMethodType
value = factory.__func__(type(self), d[attr])
setattr(self, attr, value)

It's a bit cleaner, although I'm not thrilled about having a throwaway
class, just to define a literal that ought to be provided by the
runtime.

--

Google  Where SkyNet meets Idiocracy


--
https://mail.python.org/mailman/listinfo/python-list


Re: Superclass static method name from subclass

2022-11-11 Thread Ian Pilcher

On 11/11/22 11:02, Thomas Passin wrote:

You can define a classmethod in SubClass that seems to do the job:

class SuperClass(object):
   @staticmethod
   def spam():  # "spam" and "eggs" are a Python tradition
   print('spam from SuperClass')

class SubClass(SuperClass):
     @classmethod
     def eggs(self):
     super().spam()

SubClass.eggs()  # Prints "spam from SuperClass"



That did it!  Thanks!

--

Google  Where SkyNet meets Idiocracy


--
https://mail.python.org/mailman/listinfo/python-list


Re: Superclass static method name from subclass

2022-11-11 Thread Ian Pilcher

On 11/11/22 11:29, Dieter Maurer wrote:

Ian Pilcher wrote at 2022-11-11 10:21 -0600:


   class SuperClass(object):
   @staticmethod
   def foo():
   pass

   class SubClass(SuperClass):
   bar = SuperClass.foo
 ^^

Is there a way to do this without specifically naming 'SuperClass'?


Unless you overrode it, you can use `self.foo` or `SubClass.foo`;
if you overrode it (and you are using either Python 3 or
Python 2 and a so called "new style class"), you can use `super`.
When you use `super` outside a method definition, you must
call it with parameters.


SubClass.foo doesn't work, because 'SubClass' doesn't actually exist
until the class is defined.

>>> class SubClass(SuperClass):
...   bar = SubClass.foo
...
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 2, in SubClass
NameError: name 'SubClass' is not defined. Did you mean: 'SuperClass'?

Similarly, self.foo doesn't work, because self isn't defined:

>>> class SubClass(SuperClass):
...   bar = self.foo
...
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 2, in SubClass
NameError: name 'self' is not defined

--

Google  Where SkyNet meets Idiocracy


--
https://mail.python.org/mailman/listinfo/python-list


Dealing with non-callable classmethod objects

2022-11-11 Thread Ian Pilcher

I am trying to figure out a way to gracefully deal with uncallable
classmethod objects.  The class hierarchy below illustrates the issue.
(Unfortunately, I haven't been able to come up with a shorter example.)


import datetime


class DUID(object):

_subclasses = {}

def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
cls._subclasses[cls.duid_type] = cls

def __init__(self, d):
for attr, factory in self._attrs.items():
setattr(self, attr, factory(d[attr]))

@classmethod
def from_dict(cls, d):
subcls = cls._subclasses[d['duid_type']]
return subcls(d)


class DuidLL(DUID):

@staticmethod
def _parse_l2addr(addr):
return bytes.fromhex(addr.replace(':', ''))

duid_type = 'DUID-LL'
_attrs = { 'layer2_addr': _parse_l2addr }


class DuidLLT(DuidLL):

@classmethod
def _parse_l2addr(cls, addr):
return super()._parse_l2addr(addr)

duid_type = 'DUID-LLT'
_attrs = {
'layer2_addr': _parse_l2addr,
'time': datetime.datetime.fromisoformat
}


A bit of context on why I want to do this ...

This is a simplified subset of a larger body of code that parses a
somewhat complex configuration.  The configuration is a YAML document,
that pyyaml parses into a dictionary (which contains other dictionaries,
lists, etc., etc.).  My code then parses that dictionary into an object
graph that represents the configuration.

Rather than embedding parsing logic into each of my object classes, I
have "lifted" it into the parent class (DUID in the example).  A
subclasses need only provide a few attributes that identifies its
required and optional attributes, default values, etc. (simplified to
DuidLL._attrs and DuidLLT._attrs in the example).

The parent class factory function (DUID.from_dict) uses the information
in the subclass's _attrs attribute to control how it parses the
configuration dictionary.  Importantly, a subclass's _attrs attribute
maps attribute names to "factories" that are used to parse the values
into various types of objects.

Thus, DuidLL's 'layer2_addr' attribute is parsed with its
_parse_l2addr() static method, and DuidLLT's 'time' attribute is parsed
with datetime.datetime.fromisoformat().  A factory can be any callable
object that takes a dictionary as its only argument.

This works with static methods (as well as normal functions and object
types that have an appropriate constructor):


duid_ll = DUID.from_dict({ 'duid_type': 'DUID-LL', 'layer2_addr': 
'de:ad:be:ef:00:00' })
type(duid_ll)



duid_ll.duid_type

'DUID-LL'

duid_ll.layer2_addr

b'\xde\xad\xbe\xef\x00\x00'

It doesn't work with a class method, such as DuidLLT._parse_l2addr():


duid_llt = DUID.from_dict({ 'duid_type': 'DUID-LLT', 'layer2_addr': 
'de:ad:be:ef:00:00', 'time': '2015-09-04T07:53:04-05:00' })

Traceback (most recent call last):
  File "", line 1, in 
  File "/home/pilcher/subservient/wtf/wtf.py", line 19, in from_dict
return subcls(d)
  File "/home/pilcher/subservient/wtf/wtf.py", line 14, in __init__
setattr(self, attr, factory(d[attr]))
TypeError: 'classmethod' object is not callable

In searching, I've found a few articles that discuss the fact that
classmethod objects aren't callable, but the situation actually seems to
be more complicated.

>>> type(DuidLLT._parse_l2addr)

>>> callable(DuidLLT._parse_l2addr)
True

The method itself is callable, which makes sense.  The factory function
doesn't access it directly, however, it gets it out of the _attrs
dictionary.

>>> type(DuidLLT._attrs['layer2_addr'])

>>> callable(DuidLLT._attrs['layer2_addr'])
False

I'm not 100% sure, but I believe that this is happening because the
class (DuidLLT) doesn't exist at the time that its _attrs dictionary is
defined.  Thus, there is no class to which the method can be bound at
that time and the dictionary ends up containing the "unbound version."

Fortunately, I do know the class in the context from which I actually
need to call the method, so I am able to call it with its __func__
attribute.  A modified version of DUID.__init__() appears to work:

def __init__(self, d):
for attr, factory in self._attrs.items():
if callable(factory):  # <= ???!
value = factory(d[attr])
else:
value = factory.__func__(type(self), d[attr])
setattr(self, attr, value)

A couple of questions (finally!):

* Is my analysis of why this is happening correct?

* Can I improve the 'if callable(factory):' test above?  This treats
  all non-callable objects as classmethods, which is obviously not
  correct.  Ideally, I would check specifically for a classmethod, but
  there doesn't seem to be any literal against which I could check the
  factory's type.

Note:  I am aware that there are any number of workarounds for this
issue.  I just want to make sure that I understand what is going on, and
determine if there's a 

Superclass static method name from subclass

2022-11-11 Thread Ian Pilcher

Is it possible to access the name of a superclass static method, when
defining a subclass attribute, without specifically naming the super-
class?

Contrived example:

  class SuperClass(object):
  @staticmethod
  def foo():
  pass

  class SubClass(SuperClass):
  bar = SuperClass.foo
^^

Is there a way to do this without specifically naming 'SuperClass'?

--

Google  Where SkyNet meets Idiocracy

--
https://mail.python.org/mailman/listinfo/python-list


Re: Any socket library to communicate with kernel via netlink?

2019-11-20 Thread Ian Pilcher

On 11/18/19 9:23 PM, lampahome wrote:

As title, I tried to communicate with kernel via netlink. But I failed when
I receive msg from kernel.

The weird point is sending successfully from user to kernel, failed when
receiving from kernel.

So I want to check code in 3rd library and dig in, but always found library
called netlinkg but it actually does something like modify network address
or check network card...

Any idea is welcome



https://pypi.org/project/pyroute2/

--

Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 


--
https://mail.python.org/mailman/listinfo/python-list


Distutils - bdist_rpm - specify python interpretter location

2019-10-30 Thread Ian Pilcher

I am trying to use Distutils "bdist_rpm" function on Fedora 30.  It is
failing, because Fedora does not provide a "python" executable; it
provides /usr/bin/python2 and /usr/bin/python3.

The error message is:

  env: 'python': No such file or directory
  error: Bad exit status from /var/tmp/rpm-tmp.a3xWMd (%build)

When run with the --spec-only option, one can see where 'python' is
used in the generated SPEC file:

  %build
  env CFLAGS="$RPM_OPT_FLAGS" python setup.py build

  %install
  python setup.py install -O1 --root=$RPM_BUILD_ROOT 
--record=INSTALLED_FILES


Is there a way to tell Distutils to use 'python2'?

Thanks!

--
============
Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 


--
https://mail.python.org/mailman/listinfo/python-list


Re: Get __name__ in C extension module

2019-10-07 Thread Ian Pilcher

On 10/7/19 2:09 AM, Barry Scott wrote:

I meant pass in the specific named logger that you C code will use.


Right, but I'm assuming that your C/C++ code will receive the logger
object by calling PyArg_ParseTuple (or similar), and I further assume
that you want to validate that the object actually is a logger.  Doing
that validation (by using an "O!" unit in the PyArg_ParseTuple format
string) requires access to the logging.Logger type object, and I was
unable to find a way to access that object by name.

--
========
Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 

--
https://mail.python.org/mailman/listinfo/python-list


Re: Get __name__ in C extension module

2019-10-06 Thread Ian Pilcher

On 10/6/19 12:55 PM, Barry Scott wrote:

Then the answer to your question is simple. Do it in python and passt
logger into the C++ module.


Funny thing, that's exactly where I started this journey.  I couldn't
figure out how to get the logging.Logger type object, so that I could
use a "O!" format string unit.  This led me to read a bit more about
the logging framework, which led me to the advice to get loggers by
name, rather than passing them around, etc., etc.


Next I would never code directly against the C API. Its a pain to use
and get right, get the ref counts wrong and you get memory leaks of
worse crash python.


Well, I like driving cars with manual transmissions, so ...

--
========
Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 

--
https://mail.python.org/mailman/listinfo/python-list


Re: Get __name__ in C extension module

2019-10-06 Thread Ian Pilcher

On 10/6/19 11:55 AM, MRAB wrote:
Don't you already have the module's name? You have to specify it in the 
PyModuleDef struct that you pass to PyModule_Create.


I do.  Perhaps I'm trying to be too Pythonic, but there's so much advice
out there about using getLogger(__name__) in Python code, rather than
hardcoding the name.  I've been trying to follow that pattern in my
extension module.

Calling PyModule_Create returns a reference to the module, and you can 
get its namespace dict with PyModule_GetDict(...).


Right.  I have that in my module init function, but how do I access that
later in one of my extension functions?  The only thing I can think of
would be to save it in a static variable, but static variables seem to
be a no-no in extensions.

--

Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 

--
https://mail.python.org/mailman/listinfo/python-list


Re: Get __name__ in C extension module

2019-10-06 Thread Ian Pilcher

On 10/5/19 12:55 PM, Ian Pilcher wrote:

This is straightforward, except that I cannot figure out how to retrieve
the __name__.


Making progress.  I can get a __name__ value with:

  PyDict_GetItemString(PyEval_GetGlobals(), "__name__")

I say "a __name__ value" because the returned value is actually that of
the calling module, not the name of my extension.

Is this normal?

Thanks!

--
========
Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 


--
https://mail.python.org/mailman/listinfo/python-list


Get __name__ in C extension module

2019-10-05 Thread Ian Pilcher

On 10/4/19 4:30 PM, Ian Pilcher wrote:

Ideally, I would pass my existing Logging.logger object into my C
function and use PyObject_CallMethod to call the appropriate method on
it (info, debug, etc.).


As I've researched this further, I've realized that this isn't the
correct approach.

My extension should be doing the C equivalent of:

logger = logging.getLogger(__name__)

This is straightforward, except that I cannot figure out how to retrieve
the __name__.  I can get it from the module object with
PyModule_GetName, but that requires that I have a reference to the
module object in order to do so.

I would have thought that this would be easy for a module function to
access, but I haven't been able to find any API which does this.
(Module functions get NULL as their 'self' argument.)

Any pointers appreciated.  Thanks!

--

Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 


--
https://mail.python.org/mailman/listinfo/python-list


Using a logging.Logger in a C extension

2019-10-04 Thread Ian Pilcher

I am working my way through writing a C extension, and I've realized
that I need to log a few messages from the C code.

Ideally, I would pass my existing Logging.logger object into my C
function and use PyObject_CallMethod to call the appropriate method on
it (info, debug, etc.).

PyArg_ParseTuple should be able to handle this with an "O!" format unit,
but I can't figure out how to retrieve the type object for
logging.Logger.

Any hints, links, etc. appreciated.

Thanks!

--
========
Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 


--
https://mail.python.org/mailman/listinfo/python-list


Irritating bytearray behavior

2019-09-16 Thread Ian Pilcher

I am using a bytearray to construct a very simple message, that will be
sent across the network.  The message should always be 20 bytes:

  2 bytes - address family (AF_INET or AF_INET6) - network byte order
  2 bytes - (padding)
  4 or 16 bytes - IP address

The size of the IP address is dependent on whether it is an IPv4 address
(4 bytes) or an IPv6 address (16 bytes).  In the IPv4 case, it should be
followed by 12 bytes of padding, to keep the message size consistent.

Naïvely, I thought that I could do this:

   ip = ipaddress.ip_address(unicode(addr))
   msg = bytearray(20)
   msg[1] = socket.AF_INET if ip.version == 4 else socket.AF_INET6
   msg[4:] = ip.packed
   sock.sendto(msg, dest)

This doesn't work in the IPv4 case, because the bytearray gets truncated
to only 8 bytes (4 bytes plus the size of ip.packed).

Is there a way to avoid this behavior copy the contents of ip.packed
into the bytearray without changing its size?

TIA

--

Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 


--
https://mail.python.org/mailman/listinfo/python-list


Re: The basics of the logging module mystify me

2018-04-20 Thread Ian Pilcher

On 04/19/2018 04:52 AM, Thomas Jollans wrote:

Or, more often than not, it's best to use the logging module's
configuration system that creates the right web of handlers and
formatters for you.


Wow!  This is the first I've heard of logging.config (although it's easy
to find now that I know that it exists).

As far as I can remember, none of the logging tutorials that I read ever
mentioned it.


--

Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 


--
https://mail.python.org/mailman/listinfo/python-list


Re: Spot the invalid syntax

2018-03-08 Thread Ian Pilcher

On 03/08/2018 05:30 PM, Ben Finney wrote:

Not sufficiently, it seems. Check the line preceding the ‘return’
statement.


Indeed.  :-/


Then, switch to using a programmer's text editor (I prefer Emacs) that
can spot these syntax errors while you type.


The sad thing is that I am.  Just too bone-headed to use properly,
apparently.

--

Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 


--
https://mail.python.org/mailman/listinfo/python-list


Re: Spot the invalid syntax

2018-03-08 Thread Ian Pilcher

On 03/08/2018 05:26 PM, Chris Angelico wrote:

On Fri, Mar 9, 2018 at 10:23 AM, Ian Pilcher <arequip...@gmail.com> wrote:

(Because I certainly can't.)


 ips.update(_san_dnsname_ips(cname, True)
 return ips

I've checked for tabs and mismatched parentheses.


Check the immediately preceding line (the one I quoted).

(Sometimes, you just need another pair of eyes.)



D'oh!

Clearly, my checking needs work.

Thanks mucho!

--
========
Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 


--
https://mail.python.org/mailman/listinfo/python-list


Spot the invalid syntax

2018-03-08 Thread Ian Pilcher

(Because I certainly can't.)


def _san_dnsname_ips(dnsname, dnsname_is_cname=False):
"""
Returns a set of IP addresses, managed by this IPa instance,
that correspond to the DNS name (from the subjectAltName).

"""
fqdn = dnsutil.DNSName(dnsname).make_absolute()
if fqdn.__len__() < 4:
logger.debug("Skipping IPs for %s: hostname too short" % dnsname)
return ()
zone = dnsutil.DNSName(resolver.zone_for_name(fqdn))
name = fqdn.relativize(zone)
try:
result = api.Command['dnsrecord_show'](zone, name)['result']
except errors.NotFound as nf:
logger.debug("Skipping IPs for %s: %s" % (dnsname, nf))
return ()
ips = set()
for ip in itertools.chain(result.get('arecord', ()),
  result.get('record', ())):
if _ip_rdns_ok(ip, fqdn):
ips.add(ip)
cnames = result.get('cnamerecord', ())
if cnames:
if dnsname_is_cname:
logger.debug("Skipping IPs for %s: chained CNAME" % dnsname)
else:
for cname in cnames:
if not cname.endswith('.'):
cname = u'%s.%s' % (cname, zone)
ips.update(_san_dnsname_ips(cname, True)
return ips


2.7 and 3.6 are both giving me:

  File "/tmp/test.py", line 32
return ips
 ^
SyntaxError: invalid syntax

I've checked for tabs and mismatched parentheses.

Aargh!

--
========
Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 


--
https://mail.python.org/mailman/listinfo/python-list


Re: __new__ and __init__ - why does this work?

2017-08-09 Thread Ian Pilcher

On 08/09/2017 07:54 AM, Steve D'Aprano wrote:

On Wed, 9 Aug 2017 10:08 am, Ian Pilcher wrote:


I have created a class to provide a "hash consing"[1] set.


Your footnote for [1] appears to be missing. What's a hash consing set? It
appears to be nothing more than frozen sets which you put in a cache so as to
confuse identity and value *wink*


Uugh.  Here's the link:

  https://en.wikipedia.org/wiki/Hash_consing


I doubt very much you're actually saving any time, since you create a temporary
frozen set before returning the one in the cache. You might save some memory
though.


Indeed.  This is all about using memory efficiently.


Your __init__ method does nothing. Get rid of it and save two lines of code :-)


Well, it prevents frozenset.__init__ from being called.


Also, there is at least theoretically the vague possibility that
frozenset.__init__ does something (phones home to Guido?) so you shouldn't
block it if you don't need to.


I do want to prevent frozenset.__init__ from being called *again* when
an existing instance is returned, so I've decided to take this
approach:

def __new__(cls, *args, **kwargs):
self = super(UniqueSet, cls).__new__(cls, *args, **kwargs)
self._initialized = False
return UniqueSet._registry.setdefault(self, self)

def __init__(self, *args, **kwargs):
if not self._initialized:
super(UniqueSet, self).__init__(self, *args, **kwargs)
self._initialized = True


--
========
Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 


--
https://mail.python.org/mailman/listinfo/python-list


Re: __new__ and __init__ - why does this work?

2017-08-09 Thread Ian Pilcher

On 08/08/2017 10:19 PM, Ian Kelly wrote:

It's initialized by the superclass call to __new__. frozenset is
immutable, and __init__ methods of immutable types generally don't do
anything (if they could, then they wouldn't be immutable), which is
why it doesn't really matter that you didn't call it. At the same
time, it generally doesn't hurt to call it, and you probably shouldn't
even have an override of __init__ here if it doesn't do anything.


Thanks for the explanation.

I'll admit that I'm a bit paranoid about the potential effects of
"re-__init__-ing" an object, at least in the general case.  What do
you think of this?

def __new__(cls, *args, **kwargs):
self = super(UniqueSet, cls).__new__(cls, *args, **kwargs)
self._initialized = False
return UniqueSet._registry.setdefault(self, self)

def __init__(self, *args, **kwargs):
if not self._initialized:
super(UniqueSet, self).__init__(self, *args, **kwargs)
self._initialized = True


It seems a bit inefficient that you create *two* sets in __new__ and
then map one of them to the other in your registry. Why not just
create the UniqueSet and then map it to itself if it's not already
registered? Something like this (untested):

def __new__(cls, *args, **kwargs):
 self = super(UniqueSet, cls).__new__(cls, *args, **kwargs)
 return UniqueSet._registry.setdefault(self, self)


That was mainly me being unfamiliar with the frozenset API (and not
overly concerned about the size of the _registry, since I expect that
there will be a very small number of entries).  Your version is much
more elegant.

Thank you!

--
========
Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 


--
https://mail.python.org/mailman/listinfo/python-list


__new__ and __init__ - why does this work?

2017-08-08 Thread Ian Pilcher

I have created a class to provide a "hash consing"[1] set.

  class UniqueSet(frozenset):

  _registry = dict()

  def __new__(cls, *args, **kwargs):
  set = frozenset(*args, **kwargs)
  try:
  return UniqueSet._registry[set]
  except KeyError:
  self = super(UniqueSet, cls).__new__(cls, *args, **kwargs)
  UniqueSet._registry[set] = self
  return self

  def __init__(self, *args, **kwargs):
  pass

I can't figure out how it works, though.  In particular, I can't figure
out how the call to __new__ actually initializes the set (since my
__init__ never calls the superclass __init__).

Is this a particular behavior of frozenset, or am I missing something
about the way that __new__ and __init__ interact?

--
========
Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 


--
https://mail.python.org/mailman/listinfo/python-list


Subclassing dict to modify values

2017-08-02 Thread Ian Pilcher

YANQ (Yet Another Newbie Question) ...

I would like to create a subclass of dict that modifies values as they
are inserted.  (Effectively I want to do the equivalent of "interning"
the values, although they aren't strings.)

Do I need to implement any methods other than __setitem__?  (I.e. will
any other methods/operators that add values to the dictionary call my
__setitem__ method?)

--
========
Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 


--
https://mail.python.org/mailman/listinfo/python-list


Re: Get list of attributes from list of objects?

2017-08-02 Thread Ian Pilcher

On 08/02/2017 12:49 PM, Chris Angelico wrote:

On Thu, Aug 3, 2017 at 3:21 AM, Ian Pilcher <arequip...@gmail.com> wrote:
You can't eliminate the loop, but you can compact it into a single
logical operation:

namelist = [foo.name for foo in foolist]

That's a "list comprehension", and is an elegant way to process a list
in various ways.


Very nice!  Thank you!


--
========
Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 


--
https://mail.python.org/mailman/listinfo/python-list


Get list of attributes from list of objects?

2017-08-02 Thread Ian Pilcher

Given a list of objects that all have a particular attribute, is there
a simple way to get a list of those attributes?

In other words:

  class Foo(object):
  def __init__(self, name):
  self.name = name

  foolist = [ Foo('a'), Foo('b'), Foo('c') ]

  namelist = []
  for foo in foolist:
  namelist.append(foo.name)

Is there a way to avoid the for loop and create 'namelist' with a single
expression?

--

Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 


--
https://mail.python.org/mailman/listinfo/python-list


Re: Why does Python want to read /proc/meminfo

2017-05-06 Thread Ian Pilcher

On 05/06/2017 12:51 AM, dieter wrote:

Personally, I doubt that you will find a reference.
Instead, I assume that the reference comes from the C runtime library.
It might hepl optimize memory management to know about "meminfo" details.


You're right.  Seems that it's glibc's qsort().

So it seems that any service written in Python (or any other program
that uses qsort) needs to be given read access to most of /proc or deal
with the (unspecified) consequences of not allowing qsort() to determine
the amount of memory in the system.

Delightful.

--
========
Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 

--
https://mail.python.org/mailman/listinfo/python-list


Why does Python want to read /proc/meminfo

2017-05-05 Thread Ian Pilcher

I am trying to write an SELinux policy to confine a simple service that
I have written in Python, and I'm trying to decide whether to allow or
dontaudit various denials.

To start, I've reduced my service to the simplest case:

  #!/usr/bin/python

  import sys

  sys.exit()

Running this program in a confined domain generated the following
denial:

avc:  denied  { read } for  pid=2024 comm="denatc" name="meminfo" 
dev="proc" ino=4026532028 scontext=system_u:system_r:denatc_t:s0 
tcontext=system_u:object_r:proc_t:s0 tclass=file


The program does continue on and exit cleanly, so it doesn't seem to
strictly require the access.

Does anyone know why Python is trying to access this file, or what
functionality I might be missing if I don't allow the access?

--
============
Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 

--
https://mail.python.org/mailman/listinfo/python-list


Re: cryptography default_backend is "hazmat"?

2017-03-20 Thread Ian Pilcher

On 03/19/2017 05:46 PM, Paul Moore wrote:

1. Fernet symmetric encryption, which is fine, but needs me to manage
the key safely (and offers no help in doing that) 2. X509, whose docs
are a reference (that you need to understand X509 to follow) and a
couple of tutorials on generating/requesting keys. Nothing on using
X509 for encryption.


Actually, even loading an X.509 certificate from a PEM file requires
a backend, which means delving into the "hazmat" area.

I'm not saying that some crypto functions require careful handling; they
obviously do. But is default_backend one of them?

--
========
Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 


--
https://mail.python.org/mailman/listinfo/python-list


Re: cryptography default_backend is "hazmat"?

2017-03-18 Thread Ian Pilcher

On 03/18/2017 05:15 PM, Chris Angelico wrote:

So the question is: How well do you trust the examples? Are they
likely to be instructing you in a safe way to use this
potentially-dangerous module?


But as far as I can tell, there's no way to use many of the non-hazmat
functions (e.g. parsing a certificate) without a backend, and all of the
backends are "hazmat".

So what's the point of marking something as hazmat, if a large portion
of the rest of the module can't be used without it?

--
========
Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 


--
https://mail.python.org/mailman/listinfo/python-list


cryptography default_backend is "hazmat"?

2017-03-18 Thread Ian Pilcher

Yet another newbie question/observation ...

So every example I can find of using python-cryptography includes a
call to cryptography.hazmat.backends.default_backend().  Of course, the
documentation at https://cryptography.io/en/latest/hazmat/backends/
says:

  ! Danger

  This is a “Hazardous Materials” module. You should ONLY use it if
  you’re 100% absolutely sure that you know what you’re doing because
  this module is full of land mines, dragons, and dinosaurs with laser
  guns.

Anyone else see a conflict here?

--

Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 


--
https://mail.python.org/mailman/listinfo/python-list


Re: python-daemon and PID files

2017-03-05 Thread Ian Pilcher

On 03/04/2017 11:14 PM, Chris Angelico wrote:

Why do you need a pidfile? When I get systemd to start a process, I
just have it not fork. Much easier. Forget about python-daemon - just
run your script in the simple and straight-forward way.


Because forking daemons was good enough for my grandpappy, and it ought
to be good enough you young whippersnappers today.

In other words ... facepalm.

Thanks!

--

Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 


--
https://mail.python.org/mailman/listinfo/python-list


python-daemon and PID files

2017-03-04 Thread Ian Pilcher

Is it possible to get python-daemon to create "systemd style" PID file?

I.e., systemd wants a daemon to write a file with a specific name that
*contains* the PID of the child process.  python-daemon, OTOH, seems to
use its pidfile parameter as more of a lock file.

Currently, I'm creating my PID file manually in the child process, but
systemd complains, because it wants the PID file to exist before the
parent exits.

--
========
Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 


--
https://mail.python.org/mailman/listinfo/python-list


Re: Noob confused by ConfigParser defaults

2017-02-20 Thread Ian Pilcher

On 02/20/2017 03:45 AM, Peter Otten wrote:

You can provide a default value in your code with

parser = configparser.ConfigParser()
parser.read(configfile)
value = parser.get("section-1", "option-1", fallback="default value")


Perfect.  Thank you!

--
============
Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 


--
https://mail.python.org/mailman/listinfo/python-list


Re: Noob confused by ConfigParser defaults

2017-02-20 Thread Ian Pilcher

On 02/20/2017 01:39 AM, Ben Finney wrote:

I think you misinderstand the semantics of what ‘configparser’ expects
<URL:https://docs.python.org/3/library/configparser.html#configparser-objects>:


You are absolutely correct.  Thank you!

--
========
Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 


--
https://mail.python.org/mailman/listinfo/python-list


Noob confused by ConfigParser defaults

2017-02-19 Thread Ian Pilcher

I am trying to use ConfigParser for the first time (while also writing
my first quasi-serious Python program).  Assume that I want to parse a
a configuration file of the following form:

  [section-1]
  option-1 = value1
  option-2 = value2

  [section-2]
  option-1 = value3
  option-2 = value4

How do a set a default for option-1 *only* in section-1?

--

Ian Pilcher arequip...@gmail.com
 "I grew up before Mark Zuckerberg invented friendship" 


--
https://mail.python.org/mailman/listinfo/python-list


Re: accessing elements of a tuple

2009-01-30 Thread Ian Pilcher
Matthew Sacks wrote:
 How can I access DB from the list directly using an index?

list[0][1]

... or did I misunderstand your question?

-- 

Ian Pilcher arequip...@gmail.com

--
http://mail.python.org/mailman/listinfo/python-list