2020年9月25日 星期五

[ Python 常見問題 ] Dynamic creation from string name of a class in dynamically imported module?

 Source From Here

Question
In python, I have to instantiate certain class, knowing its name in a string, but this class 'lives' in a dynamically imported module. How to do it?

HowTo
You can use getattr to access the attributes of loaded module. Consider you have module below:
my_mod.py
  1. class MyClass:  
  2.     def __init__(self, name, age):  
  3.         self.name = name  
  4.         self.age = age  
  5.   
  6.     def __str__(self):  
  7.         return f"My name is {self.name} and my age is {self.age}"  
The default way to use this module:
>>> from my_mod import *
>>> john = MyClass('John', 40)
>>> print(john)
My name is John and my age is 40

To access the module my_mod and create object of class MyClass dynamically:
>>> my_mod = __import__('my_mod')
>>> my_clz = getattr(my_mod, 'MyClass')
>>> john = my_clz('John', 40)
>>> print(john)
My name is John and my age is 40
Or you can leverage another package importlib:
  1. import importlib  
  2. module = importlib.import_module(module_name)  
  3. class_ = getattr(module, class_name)  
  4. instance = class_()  


[ Python 常見問題 ] How to share an Anaconda Python environment between multiple users?

 Source From Here

Question
I have Anaconda 5.1 Python distribution installed (by the system admin) on Windows 10, for all users. I can create an environment and then view the available environments:
# conda create --name py35 python=3.5 anaconda
...
# conda env list
# conda environments:
#
base * C:\ProgramData\Anaconda3
py35 C:\Users\<my-user-name>\AppData\Local\conda\conda\envs\py35

When I log in as a different user, however, only the base environment is visible/available. How can I create an environment and make it available to all users of the system?

The documentation discusses multi-user installations, but I cannot see how to make environments available to other users.

How-To
(Installation of conda) I would shy away from sharing environments with other users, because if they don't know what they are doing, they could add packages that could conflict with other packages and/or even delete packages that another user might need. The preferred approach is that after you have created an environment, you export it as a yml file. (doc - sharing an environment) For example:
$ conda env list
# conda environments:
#
base * /opt/anaconda3


$ mkdir /conda_env/

// -p PATH, --prefix PATH: Full path to environment location (i.e. prefix).
$ conda create -p /conda_env/my_env python=python3.7
$ conda activate /conda_env/my_env/
(/conda_env/my_env) $ conda install numpy
(/conda_env/my_env) $ python -c "import numpy as np; print(np.__version__)"
1.19.1

(/conda_env/my_env) $ conda env export > environment.yml
(/conda_env/my_env) $ cat environment.yml
  1. name: /conda_env/my_env  
  2. channels:  
  3.   - defaults  
  4. dependencies:  
  5.   - _libgcc_mutex=0.1=main  
  6.   - blas=1.0=mkl  
  7.   - ca-certificates=2020.7.22=0  
  8.   - certifi=2020.6.20=py38_0  
  9.   - intel-openmp=2020.2=254  
  10.   - ld_impl_linux-64=2.33.1=h53a641e_7  
  11.   - libedit=3.1.20191231=h14c3975_1  
  12.   - libffi=3.3=he6710b0_2  
  13.   - libgcc-ng=9.1.0=hdf63c60_0  
  14.   - libstdcxx-ng=9.1.0=hdf63c60_0  
  15.   - mkl=2020.2=256  
  16.   - mkl-service=2.3.0=py38he904b0f_0  
  17.   - mkl_fft=1.2.0=py38h23d657b_0  
  18.   - mkl_random=1.1.1=py38h0573a6f_0  
  19.   - ncurses=6.2=he6710b0_1  
  20.   - numpy=1.19.1=py38hbc911f0_0  
  21.   - numpy-base=1.19.1=py38hfa32c7d_0  
  22.   - openssl=1.1.1h=h7b6447c_0  
  23.   - pip=20.2.2=py38_0  
  24.   - python=3.8.5=h7579374_1  
  25.   - readline=8.0=h7b6447c_0  
  26.   - setuptools=49.6.0=py38_0  
  27.   - six=1.15.0=py_0  
  28.   - sqlite=3.33.0=h62c20be_0  
  29.   - tk=8.6.10=hbc83047_0  
  30.   - wheel=0.35.1=py_0  
  31.   - xz=5.2.5=h7b6447c_0  
  32.   - zlib=1.2.11=h7b6447c_3  
  33. prefix: /conda_env/my_env  
// Exit conda virtual environment
(/conda_env/my_env) $ conda deactivate

Then you send the users the yml file and have them build their own environment using the yml:
$ conda env create -f environment.yml

If you really want to use a shared environment where every user can access, we have to make sure the user has proper right to access the created conda virtual environment:
// Create a group for conda virtual environment
# groupadd conda_user

// Change the permission of target folder to be accessible by the created group
# chown root:conda_user -R /conda_env/my_env/
# chmod -R 775 /conda_env/my_env/

// Add the target user into created group
# usermod -a -G conda_user john

Then let's switch to another user `john` to make sure he can use our created conda virtual environment:
// Now we are using account john
// Let's activate the conda virtual environment
$ conda activate /conda_env/my_env/

// Confirm the numpy version is the same as the installed one previously
(/conda_env/my_env) $ python -c "import numpy as np; print(np.__version__)"
1.19.1

// Let's install another package coloredlogs
(/conda_env/my_env) $ python -c "import numpy as np; print(np.__version__)"
(/conda_env/my_env) $ python -c "import coloredlogs; print(coloredlogs.__version__)"
14.0
// Exit conda virtualenv
(/conda_env/my_env) $ conda deactivate

So far so good, let's use first account root to verify that the package installed by john account can be used by root too:
// Switch to account root and activate conda virtual environment
# conda activate /conda_env/my_env/
(/conda_env/my_env) # python -c "import coloredlogs; print(coloredlogs.__version__)"
14.0

Great! Everything works.

Supplement
FAQ - how to specify new environment location for conda create

[Linux 文章收集] How to List Groups in Linux

 Source From Here

Preface
In Linux, a group is a collection of users. The main purpose of the groups is to define a set of privileges like read, write, or execute permission for a given resource that can be shared among the users within the group. Users can be added to an existing group to utilize the privileges it grants.

This tutorial explains how to show all groups a user is a member of. We will also explain how to list all members of a group.

Linux Groups
There are two types of groups that a user can belong to:
Primary or login group – is the group that is assigned to the files that are created by the user. Usually, the name of the primary group is the same as the name of the user. Each user must belong to exactly one primary group.
Secondary or supplementary group - used to grant certain privileges to a set of users. A user can be a member of zero or more secondary groups.


List all Groups a User is a Member of
There are multiple ways to find out the groups a user belongs to.

The primary user’s group is stored in the /etc/passwd file and the supplementary groups, if any, are listed in the /etc/group file. One way to find the user’s groups is to list the contents of those files using cat , less or grep . Another easier option is to use a command whose purpose is to provide information about the system’s users and groups.

Using the groups command
The most memorable command to list all groups a user is a member of is the groups command. When executed without an argument the command will print a list of all groups the currently logged in user belongs to:
$ groups
john adm cdrom sudo dip plugdev lpadmin sambashare

To get a list of all groups a specific user belongs to, provide the username to the groups command as an argument:
$ groups john
john : john test docker admin_user

Using the id command
The id command prints information about the specified user and its groups. If the username is omitted it shows information for the current user. For example to get information about the user john you would type:
# id john
uid=1001(john) gid=1001(john) groups=1001(john),1000(test),972(docker),1002(admin_user)

To print only the names instead of the numbers use the -n option. Option -g will print only the primary group and -G all groups:
# id -nG john
john test docker admin_user

List All Members of a Group
To list all members of a group, use the getent group command followed by the group name. For example, to find out the members of a group with the name admin_user you would use the following command:
# getent group admin_user
admin_user:x:1002:john,root

List All Groups
To view all groups present on the system simply open the /etc/group file. Each line in this file represents information for one group:
$ less /etc/group

Another option is to use the getent command which displays entries from databases configured in /etc/nsswitch.conf file including the group database which we can use to query a list of all groups. To get a list of all groups, type the following command:
$ getent group

The output is the same as when displaying the content of the /etc/group file. If you are using LDAP for user authentication the getent will display all groups from both /etc/group file and LDAP database.

You can also use awk or cut to print only the first field containing the name of the group:
$ getent group | awk -F: '{ print $1}'
$ getent group | cut -d: -f1

Supplement
Add a User to a Group (or Second Group) on Linux
How to create users and groups in Linux from the command line

[ Python 常見問題 ] Aliases for commands with Python cmd module

 Source From Here

Question
How can I create an alias for a command in a line-oriented command interpreter implemented using the cmd module?

To create a command, I must implement the do_cmd method. But I have commands with long names (like constraint) and I want to provide aliases (in fact, shortcuts) for these commands (like co). How can I do that? One possibility that came to my mind is to implement the do_alias (like do_co) method and just calling do_cmd (do_constraint) in this method. But this brings me new commands in the help of the CLI.

Is there any other way to achieve this? Or may be is there a way to hide commands from the help output?

HowTo
You can overwrite the default method and search for a suitable command handler (as already suggested by Brian):
  1. import cmd  
  2. import sys  
  3.   
  4. class WithAliasCmd(cmd.Cmd):  
  5.     def do_long_cmd_name(self, arg):  
  6.         print("Hello world!")  
  7.   
  8.     def default(self, line):  
  9.         cmd, arg, line = self.parseline(line)  
  10.         func = [getattr(self, n) for n in self.get_names() if n.startswith('do_' + cmd)]  
  11.         if func: # maybe check if exactly one or more elements, and tell the user  
  12.             func[0](arg)  
  13.         elif cmd == "hello": # "hello" is an alias for command long_cmd_name  
  14.             return self.do_long_cmd_name(arg)  
  15.   
  16.     def do_bye(self, arg):  
  17.         print("Bye")  
  18.         return True  
  19.   
  20.   
  21. if __name__ == '__main__':  
  22.     WithAliasCmd().cmdloop()  
Execution output:
C:\tmp> python cmd_alias.py
(Cmd) ?

Documented commands (type help <topic>):
========================================
help

Undocumented commands:
======================
bye long_cmd_name


(Cmd) long_cmd_name
Hello world!
(Cmd) hello
Hello world!


[ Python 常見問題 ] When using unittest.mock.patch, why is autospec not True by default?

  Source From  Here Question When you patch a function using  mock , you have the option to specify  autospec  as True: If you set  autospec...