Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
superhelp
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Grant Paton-Simpson
superhelp
Commits
2cde7cd2
Commit
2cde7cd2
authored
May 01, 2020
by
Grant Paton-Simpson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Streamline and standardise message making; misc bug fixes; bump version
parent
de738baa
Pipeline
#561
failed with stages
Changes
27
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
27 changed files
with
1177 additions
and
1003 deletions
+1177
-1003
Makefile
Makefile
+1
-1
README.md
README.md
+1
-1
setup.py
setup.py
+1
-1
superhelp/advisors/class_advisors.py
superhelp/advisors/class_advisors.py
+109
-91
superhelp/advisors/decorator_advisors.py
superhelp/advisors/decorator_advisors.py
+8
-5
superhelp/advisors/dict_advisors.py
superhelp/advisors/dict_advisors.py
+112
-143
superhelp/advisors/enumerate_advisors.py
superhelp/advisors/enumerate_advisors.py
+6
-6
superhelp/advisors/exception_advisors.py
superhelp/advisors/exception_advisors.py
+33
-31
superhelp/advisors/for_advisors.py
superhelp/advisors/for_advisors.py
+27
-18
superhelp/advisors/func_advisors.py
superhelp/advisors/func_advisors.py
+187
-148
superhelp/advisors/if_else_advisors.py
superhelp/advisors/if_else_advisors.py
+139
-122
superhelp/advisors/list_advisors.py
superhelp/advisors/list_advisors.py
+39
-40
superhelp/advisors/listcomp_advisors.py
superhelp/advisors/listcomp_advisors.py
+32
-25
superhelp/advisors/name_advisors.py
superhelp/advisors/name_advisors.py
+46
-23
superhelp/advisors/named_tuple_advisors.py
superhelp/advisors/named_tuple_advisors.py
+28
-10
superhelp/advisors/nested_advisors.py
superhelp/advisors/nested_advisors.py
+53
-56
superhelp/advisors/num_advisors.py
superhelp/advisors/num_advisors.py
+34
-19
superhelp/advisors/packing_advisors.py
superhelp/advisors/packing_advisors.py
+28
-11
superhelp/advisors/set_advisors.py
superhelp/advisors/set_advisors.py
+51
-41
superhelp/advisors/sorting_reversing_advisors.py
superhelp/advisors/sorting_reversing_advisors.py
+46
-37
superhelp/advisors/str_advisors.py
superhelp/advisors/str_advisors.py
+73
-58
superhelp/advisors/tuple_advisors.py
superhelp/advisors/tuple_advisors.py
+41
-36
superhelp/conf.py
superhelp/conf.py
+15
-75
superhelp/messages.py
superhelp/messages.py
+1
-1
tests/test_funcs.py
tests/test_funcs.py
+32
-0
tests/test_if_elses.py
tests/test_if_elses.py
+26
-4
tests/test_sets.py
tests/test_sets.py
+8
-0
No files found.
Makefile
View file @
2cde7cd2
git
:
cd
/home/g/projects/superhelp
&&
nosetests
/home/g/projects/superhelp/superhelp/env/bin/
nosetests
sed
-i
's/^test_misc()/# test_misc()/'
/home/g/projects/superhelp/tests/
*
.py
sed
-i
's/RECORD_AST = t/RECORD_AST = f/'
/home/g/projects/superhelp/superhelp/conf.py
sed
-i
's/DEV_MODE = t/DEV_MODE = f/'
/home/g/projects/superhelp/superhelp/conf.py
...
...
README.md
View file @
2cde7cd2
# https://git.nzoss.org.nz/pyGrant/superhelp
version number: 0.9.
1
version number: 0.9.
2
author: Grant Paton-Simpson
## Overview
...
...
setup.py
View file @
2cde7cd2
...
...
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages # @UnresolvedImport
from
codecs
import
open
from
os
import
path
__version__
=
'0.9.
1
'
__version__
=
'0.9.
2
'
here
=
path
.
abspath
(
path
.
dirname
(
__file__
))
...
...
superhelp/advisors/class_advisors.py
View file @
2cde7cd2
...
...
@@ -27,65 +27,67 @@ def getters_setters(block_dets, *, repeated_message=False):
class_getter_setter_methods
[
class_name
].
append
(
method_name
)
if
not
class_getter_setter_methods
:
return
None
brief_msg
=
layout
(
"""
\
title
=
layout
(
"""
\
### Alternative to getters and setters
"""
)
simple_class_msg_bits
=
[]
for
class_name
,
method_names
in
sorted
(
class_getter_setter_methods
.
items
()):
multiple
=
len
(
method_names
)
>
1
if
multiple
:
nice_list
=
get_nice_str_list
(
method_names
,
quoter
=
'`'
)
brief_msg
+=
layout
(
f
"""
\
simple_class_msg_bits
.
append
(
layout
(
f
"""
\
Class `
{
class_name
}
` has the following methods that look like
either getters or setters:
{
nice_list
}
.
"""
)
"""
)
)
else
:
method_type
=
(
'getter'
if
method_name
.
startswith
(
'get_'
)
else
'setter'
)
brief_msg
+=
layout
(
f
"""
\
simple_class_msg_bits
.
append
(
layout
(
f
"""
\
Class `
{
class_name
}
` has a `
{
method_names
[
0
]
}
` method that
looks like a
{
method_type
}
.
"""
)
"""
))
simple_class_msg
=
''
.
join
(
simple_class_msg_bits
)
if
not
repeated_message
:
brief_msg
+
=
layout
(
"""
\
properties_option
=
layout
(
"""
\
Python doesn't need getters and setters. Instead, you can use
properties. These are easily added using decorators e.g.
`@property`.
"""
)
main_msg
=
brief_msg
if
not
repeated_message
:
tm
=
'
\N{TRADE MARK SIGN}
'
main_msg
+=
(
why_getters_etc
=
layout
(
f
"""
\
A good discussion of getters, setters, and properties can be found
at <https://www.python-course.eu/python3_properties.php>.
Getters and setters are usually added in other languages such as
Java because direct attribute access doesn't give the ability to
calculate results or otherwise run a process when a value is
accessed / written.
And it is common for lots of getters and setters to be added,
whether or not they are actually needed - Just In Case
{
tm
}
. The fear
is that if you point other code to an attribute, and you later need
to process the attribute or derive it before it is served up or
stored, then you'll need to make a breaking change to your code. All
the client code referencing the attribute will have to be rewritten
to replace direct access with a reference to the appropriate getter
or setter. Understandably then the inclination is to point to a
getter or setter in the first case even if it doesn't actually do
anything different (for now at least) from direct access. Using
these getters and setters is wasteful, and bloats code
unnecessarily, but it avoids the worse evil of regularly broken
interfaces. The benefit is that you can change implementation later
if you need to and nothing will break. But in Python there is a much
better way :-).
"""
)
comparison
=
(
layout
(
f
"""
\
A good discussion of getters, setters, and properties can be
found at <https://www.python-course.eu/python3_properties.php>.
Getters and setters are usually added in other languages such as
Java because direct attribute access doesn't give the ability to
calculate results or otherwise run a process when a value is
accessed / written.
And it is common for lots of getters and setters to be added,
whether or not they are actually needed - Just In Case
{
tm
}
. The
fear is that if you point other code to an attribute, and you
later need to process the attribute or derive it before it is
served up or stored, then you'll need to make a breaking change
to your code. All the client code referencing the attribute will
have to be rewritten to replace direct access with a reference
to the appropriate getter or setter. Understandably then the
inclination is to point to a getter or setter in the first case
even if it doesn't actually do anything different (for now at
least) from direct access. Using these getters and setters is
wasteful, and bloats code unnecessarily, but it avoids the worse
evil of regularly broken interfaces. The benefit is that you can
change implementation later if you need to and nothing will
break. But in Python there is a much better way :-).
Let's compare the getter / setter approach and the property
approach.
...
...
@@ -168,28 +170,35 @@ def getters_setters(block_dets, *, repeated_message=False):
"""
,
is_code
=
True
)
)
if
repeated_message
:
extra_msg
=
''
else
:
extra_msg
=
(
layout
(
"""
\
Python also has a `deleter` decorator which handle deletion
of the attribute e.g.
"""
)
+
layout
(
"""
\
@name.deleter
def name(self):
...
"""
,
is_code
=
True
)
)
message
=
{
conf
.
BRIEF
:
brief_msg
,
conf
.
MAIN
:
main_msg
,
conf
.
EXTRA
:
extra_msg
,
}
return
message
deleter
=
(
layout
(
"""
\
Python also has a `deleter` decorator which handle deletion of
the attribute e.g.
"""
)
+
layout
(
"""
\
@name.deleter
def name(self):
...
"""
,
is_code
=
True
)
)
else
:
properties_option
=
''
why_getters_etc
=
''
comparison
=
''
deleter
=
''
brief_msg
=
title
+
simple_class_msg
+
properties_option
main_msg
=
(
title
+
simple_class_msg
+
properties_option
+
why_getters_etc
+
comparison
)
extra_msg
=
deleter
message
=
{
conf
.
BRIEF
:
brief_msg
,
conf
.
MAIN
:
main_msg
,
conf
.
EXTRA
:
extra_msg
,
}
return
message
@
filt_block_advisor
(
xpath
=
CLASS_XPATH
,
warning
=
True
)
def
selfless_methods
(
block_dets
,
*
,
repeated_message
=
False
):
...
...
@@ -218,28 +227,31 @@ def selfless_methods(block_dets, *, repeated_message=False):
class_selfless_methods
[
class_name
].
append
(
method_name
)
if
not
class_selfless_methods
:
return
None
brief_msg
=
layout
(
"""
\
title
=
layout
(
"""
\
### Method doesn't use instance
"""
)
simple_class_msg_bits
=
[]
for
class_name
,
method_names
in
sorted
(
class_selfless_methods
.
items
()):
multiple
=
len
(
method_names
)
>
1
if
multiple
:
nice_list
=
get_nice_str_list
(
method_names
,
quoter
=
'`'
)
brief_msg
+=
layout
(
f
"""
\
simple_class_msg_bits
.
append
(
layout
(
f
"""
\
Class `
{
class_name
}
` has the following methods that don't use
the instance (usually called `self`):
{
nice_list
}
.
"""
)
"""
)
)
else
:
brief_msg
+=
layout
(
f
"""
\
simple_class_msg_bits
.
append
(
layout
(
f
"""
\
Class `
{
class_name
}
` has a `
{
method_names
[
0
]
}
` method that
doesn't use the instance (usually called `self`).
"""
)
"""
))
simple_class_msg
=
''
.
join
(
simple_class_msg_bits
)
if
not
repeated_message
:
brief_msg
+
=
layout
(
"""
\
staticmethod_msg
=
layout
(
"""
\
If a method doesn't use the instance it can be either pulled into a
function outside the class definition or decorated with
...
...
@@ -247,10 +259,7 @@ def selfless_methods(block_dets, *, repeated_message=False):
instance object to be supplied as the first argument.
"""
)
main_msg
=
brief_msg
if
not
repeated_message
:
main_msg
+=
(
staticmethod_demo
=
(
layout
(
"""
For example, instead of:
...
...
@@ -274,15 +283,19 @@ def selfless_methods(block_dets, *, repeated_message=False):
return round(years * 365.25)
"""
,
is_code
=
True
)
)
if
repeated_message
:
extra_msg
=
''
else
:
extra_msg
=
layout
(
"""
\
call_it_self
=
layout
(
"""
\
It is not obligatory to call the first parameter of a bound method
`self` but you should call it that unless you have a good reason to
break convention.
"""
)
else
:
staticmethod_msg
=
''
staticmethod_demo
=
''
call_it_self
=
''
brief_msg
=
title
+
simple_class_msg
+
staticmethod_msg
main_msg
=
title
+
simple_class_msg
+
staticmethod_msg
+
staticmethod_demo
extra_msg
=
call_it_self
message
=
{
conf
.
BRIEF
:
brief_msg
,
conf
.
MAIN
:
main_msg
,
...
...
@@ -315,11 +328,12 @@ def one_method_classes(block_dets, *, repeated_message=False):
classes_sole_methods
.
append
((
class_name
,
sole_method_name
))
if
not
classes_sole_methods
:
return
None
multi_sole
=
len
(
classes_sole_methods
)
>
1
class_plural
=
'es'
if
multi_sole
else
''
class_have_has
=
'have'
if
multi_sole
else
'has'
func_plural
=
's'
if
multi_sole
else
''
brief_msg
=
layout
(
f
"""
\
summary
=
layout
(
f
"""
\
### Possible option of converting class
{
class_plural
}
to single function
{
func_plural
}
...
...
@@ -327,16 +341,29 @@ def one_method_classes(block_dets, *, repeated_message=False):
function at most (excluding `__init__`):
"""
)
n_methods_msg_bits
=
[]
for
class_name
,
method_name
in
classes_sole_methods
:
method2use
=
(
f
"`
{
method_name
}
`"
if
method_name
else
'nothing but `__init__`'
)
brief_msg
+=
layout
(
f
"""
\
n_methods_msg_bits
.
append
(
layout
(
f
"""
\
-
{
class_name
}
:
{
method2use
}
"""
)
if
repeated_message
:
extra_msg
=
''
else
:
brief_msg
+=
(
"""
))
n_methods_msg
=
''
.
join
(
n_methods_msg_bits
)
if
not
repeated_message
:
not_just_oo
=
layout
(
"""
\
Python allows procedural, object-oriented, and functional styles of
programming. Event-based programming is also used in GUI contexts,
for example. Programmers coming to Python from languages that only
support object-orientation sometimes overdo the classes when there
is a simpler, more elegant way of writing readable code in Python.
If only a simple function is required, then write a simple function.
Note - there may be exceptions. It has been suggested that the class
structure can make it easier to test intermediate state rather than
just function outputs. So, as with most things, it depends.
"""
)
function_demo
=
(
layout
(
f
"""
\
It may be simpler to replace the class
{
class_plural
}
with simple
...
...
@@ -378,21 +405,12 @@ def one_method_classes(block_dets, *, repeated_message=False):
"""
)
)
extra_msg
=
layout
(
"""
\
Python allows procedural, object-oriented, and functional styles of
programming. Event-based programming is also used in GUI contexts,
for example. Programmers coming to Python from languages that only
support object-orientation sometimes overdo the classes when there
is a simpler, more elegant way of writing readable code in Python.
If only a simple function is required, then write a simple function.
else
:
not_just_oo
=
''
function_demo
=
''
Note - there may be exceptions. It has been suggested that the class
structure can make it easier to test intermediate state rather than
just function outputs. So, as with most things, it depends.
"""
)
message
=
{
conf
.
BRIEF
:
brief_msg
,
conf
.
EXTRA
:
extra_msg
,
conf
.
BRIEF
:
summary
+
n_methods_msg
+
function_demo
,
conf
.
EXTRA
:
not_just_oo
,
}
return
message
superhelp/advisors/decorator_advisors.py
View file @
2cde7cd2
...
...
@@ -28,16 +28,16 @@ def decorator_overview(block_dets, *, repeated_message=False):
if
namespace
:
name
=
f
"
{
namespace
}
.
{
name
}
"
decorator_names
.
append
(
name
)
dec_name_list
=
get_nice_str_list
(
decorator_names
,
quoter
=
'`'
)
plural
=
's'
if
len
(
decorator_names
)
>
1
else
''
brief_msg
=
layout
(
f
"""
\
summary
=
layout
(
f
"""
\
### Decorator
{
plural
}
used
The code uses the decorator
{
plural
}
:
{
dec_name_list
}
.
"""
)
main_msg
=
brief_msg
if
not
repeated_message
:
main_msg
+
=
(
dec_dets
=
(
layout
(
"""
\
Decorators are a common and handy feature of Python. Using them
...
...
@@ -95,8 +95,11 @@ def decorator_overview(block_dets, *, repeated_message=False):
say("sausage!")
'''
,
is_code
=
True
)
)
else
:
dec_dets
=
''
message
=
{
conf
.
BRIEF
:
brief_msg
,
conf
.
MAIN
:
main_msg
,
conf
.
BRIEF
:
summary
,
conf
.
MAIN
:
summary
+
dec_dets
,
}
return
message
superhelp/advisors/dict_advisors.py
View file @
2cde7cd2
...
...
@@ -5,137 +5,116 @@ from ..utils import get_nice_str_list, layout_comment as layout
ASSIGN_DICT_XPATH
=
'descendant-or-self::Assign/value/Dict'
def
_get_additional_main_msg
(
first_name
):
additional_main_msg
=
(
layout
(
f
"""
It is common to iterate through the key-value pairs of a dictionary.
This can be achieved using the dictionary's `.items()` method. E.g.
"""
)
+
layout
(
f
"""
\
## k, v is conventional, and OK in a hurry, but readable names
## are probably better for code you're going to maintain
for k, v in
{
first_name
}
.items():
print(f"key {{k}} maps to value {{v}}")
"""
,
is_code
=
True
)
+
layout
(
f
"""
Keys are unique but values can be repeated. For example:
"""
)
+
layout
(
f
"""
country2car = {{'Japan': 'Toyota', 'Sweden': 'Volvo'}} ## OK - all keys are unique
country2car = {{'Japan': 'Toyota', 'Japan': 'Honda'}} ## Oops - the 'Japan' key is repeated
"""
,
is_code
=
True
)
+
layout
(
f
"""
@
filt_block_advisor
(
xpath
=
ASSIGN_DICT_XPATH
)
def
dict_overview
(
block_dets
,
*
,
repeated_message
=
False
):
"""
Look at assigned dictionaries e.g. location = {'country' 'New Zealand',
'city': 'Auckland'}
"""
dict_els
=
block_dets
.
element
.
xpath
(
ASSIGN_DICT_XPATH
)
plural
=
'ies'
if
len
(
dict_els
)
>
1
else
'y'
title
=
layout
(
f
"""
\
In which case a better structure might be to have each 'value'
being a list e.g.
### Dictionar
{
plural
}
defined
"""
)
+
layout
(
f
"""
country2cars = {{'Japan': ['Toyota', 'Honda'], 'Sweden': ['Volvo']}} ## OK - all keys are unique
"""
,
is_code
=
True
)
)
return
additional_main_msg
def
_get_minimal_dict_details
(
block_dets
,
dict_els
,
plural
):
brief_msg
=
''
for
i
,
dict_el
in
enumerate
(
dict_els
):
first
=
(
i
==
0
)
"""
)
brief_desc_bits
=
[]
for
dict_el
in
dict_els
:
name
=
get_assign_name
(
dict_el
)
items
=
code_execution
.
get_val
(
block_dets
.
pre_block_code_str
,
block_dets
.
block_code_str
,
name
)
if
first
:
title
=
layout
(
f
"""
\
### Dictionar
{
plural
}
defined
"""
)
brief_msg
+=
title
brief_msg
+=
layout
(
f
"""
\
brief_desc_bits
.
append
(
layout
(
f
"""
\
`
{
name
}
` is a dictionary with
{
utils
.
int2nice
(
len
(
items
))
}
items
(i.e.
{
utils
.
int2nice
(
len
(
items
))
}
mappings).
"""
)
message
=
{
conf
.
BRIEF
:
brief_msg
,
}
return
message
"""
))
brief_desc
=
''
.
join
(
brief_desc_bits
)
if
not
repeated_message
:
dict_def
=
layout
(
"""
\
def
_get_full_dict_details
(
block_dets
,
dict_els
,
plural
):
brief_msg
=
''
main_msg
=
''
first_name
=
None
for
i
,
dict_el
in
enumerate
(
dict_els
):
first
=
(
i
==
0
)
name
=
get_assign_name
(
dict_el
)
items
=
code_execution
.
get_val
(
block_dets
.
pre_block_code_str
,
block_dets
.
block_code_str
,
name
)
if
first
:
first_name
=
name
title
=
layout
(
f
"""
\
Dictionaries map keys to values.
### Dictionar
{
plural
}
defined
"""
)
workhorses
=
layout
(
"""
\
"""
)
brief_msg
+=
title
main_msg
+=
title
Dictionaries, along with lists, are the workhorses of Python data
structures.
"""
)
keys_and_vals
=
layout
(
"""
\
brief_msg
+=
layout
(
"""
\
Keys are unique but values can be repeated.
Dictionaries map keys to values.
"""
)
dict_desc_bits
=
[]
for
i
,
dict_el
in
enumerate
(
dict_els
):
name
=
get_assign_name
(
dict_el
)
if
i
==
0
:
first_name
=
name
items
=
code_execution
.
get_val
(
block_dets
.
pre_block_code_str
,
block_dets
.
block_code_str
,
name
)
empty_dict
=
(
len
(
items
)
==
0
)
if
empty_dict
:
dict_desc_bits
.
append
(
layout
(
f
"""
\
`
{
name
}
` is an empty dictionary.
"""
))
else
:
plural
=
''
if
len
(
items
)
==
1
else
's'
dict_desc_bits
.
append
(
layout
(
f
"""
\
`
{
name
}
` is a dictionary with
{
utils
.
int2nice
(
len
(
items
))
}
item
{
plural
}
(i.e.
{
utils
.
int2nice
(
len
(
items
))
}
mapping
{
plural
}
). In this case, the keys are:
{
list
(
items
.
keys
())
}
. We can get the keys using the `.keys()`
method e.g. `
{
name
}
`.`keys()`. The values are
{
list
(
items
.
values
())
}
. We can get the values using the
`.values()` method e.g. `
{
name
}
`.`values()`.
"""
))
main_dict_desc
=
''
.
join
(
dict_desc_bits
)
general
=
(
layout
(
f
"""
It is common to iterate through the key-value pairs of a
dictionary. This can be achieved using the dictionary's
`.items()` method. E.g.
"""
)
main_msg
+=
layout
(
"""
\
Dictionaries, along with lists, are the workhorses of Python
data structures.
+
layout
(
f
"""
\
## k, v is conventional, and OK in a hurry, but readable names
## are probably better for code you're going to maintain
for k, v in
{
first_name
}
.items():
print(f"key {{k}} maps to value {{v}}")
"""
,
is_code
=
True
)
+
layout
(
f
"""
Keys are unique but values can be repeated. For example:
"""
)
empty_dict
=
(
len
(
items
)
==
0
)
if
empty_dict
:
list_desc
=
layout
(
f
"""
\
+
layout
(
f
"""
country2car = {{'Japan': 'Toyota', 'Sweden': 'Volvo'}} ## OK - all keys are unique
country2car = {{'Japan': 'Toyota', 'Japan': 'Honda'}} ## Oops - the 'Japan' key is repeated
`
{
name
}
` is an empty dictionary.
"""
,
is_code
=
True
)
+
layout
(
f
"""
"""
)
else
:
plural
=
''
if
len
(
items
)
==
1
else
's'
list_desc
=
layout
(
f
"""
\
`
{
name
}
` is a dictionary with
{
utils
.
int2nice
(
len
(
items
))
}
item
{
plural
}
(i.e.
{
utils
.
int2nice
(
len
(
items
))
}
mapping
{
plural
}
). In this case, the keys are:
{
list
(
items
.
keys
())
}
. We can get the keys using the `.keys()`
method e.g. `
{
name
}
`.`keys()`. The values are
{
list
(
items
.
values
())
}
. We can get the values using the
`.values()` method e.g. `
{
name
}
`.`values()`.
In which case a better structure might be to have each 'value'
being a list e.g.
"""
)
brief_msg
+=
list_desc
main_msg
+=
list_desc
brief_msg
+=
layout
(
"""
\
Keys are unique but values can be repeated.
+
layout
(
f
"""
country2cars = {{'Japan': ['Toyota', 'Honda'], 'Sweden': ['Volvo']}} ## OK - all keys are unique
Dictionaries, along with lists, are the workhorses of Python data
structures.
"""
)
main_msg
+=
_get_additional_main_msg
(
first_name
)
message
=
{
conf
.
BRIEF
:
brief_msg
,
conf
.
MAIN
:
main_msg
,
conf
.
EXTRA
:
layout
(
"""
\
"""
,
is_code
=
True
)
)
mighty_dict
=
layout
(
"""
\
Python dictionaries (now) keep the order in which items are added.
...
...
@@ -147,21 +126,19 @@ def _get_full_dict_details(block_dets, dict_els, plural):
2. The Mighty Dictionary -
<https://www.youtube.com/watch?v=oMyy4Sm0uBs>
"""
)
}
return
message
@
filt_block_advisor
(
xpath
=
ASSIGN_DICT_XPATH
)
def
dict_overview
(
block_dets
,
*
,
repeated_message
=
False
):
"""
Look at assigned dictionaries e.g. location = {'country' 'New Zealand',
'city': 'Auckland'}
"""
dict_els
=
block_dets
.
element
.
xpath
(
ASSIGN_DICT_XPATH
)
plural
=
'ies'
if
len
(
dict_els
)
>
1
else
'y'
if
repeated_message
:
message
=
_get_minimal_dict_details
(
block_dets
,
dict_els
,
plural
)
else
:
message
=
_get_full_dict_details
(
block_dets
,
dict_els
,
plural
)
dict_def
=
''
workhorses
=
''
keys_and_vals
=
''
main_dict_desc
=
brief_desc
general
=
''
mighty_dict
=
''
message
=
{
conf
.
BRIEF
:
title
+
dict_def
+
brief_desc
+
keys_and_vals
+
workhorses
,
conf
.
MAIN
:
title
+
main_dict_desc
+
workhorses
+
general
,
conf
.
EXTRA
:
mighty_dict
,
}
return
message
def
get_key_type_names
(
items
):
...
...
@@ -179,12 +156,8 @@ def mixed_key_types(block_dets, *, repeated_message=False):
Warns about dictionaries with mix of string and integer keys.
"""