I have form:
class Form(forms.ModelForm):
id = forms.ModelChoiceField(queryset=Category.objects.all(), widget=forms.HiddenInput())
def choices(self):
items = ...query for items...
for il in items:
prefix = ''
choices = []
for i in range(0,il.depth):
prefix = prefix + " "
il.name = prefix + il.name
choices.append((il.id,il.language))
self.fields['parent'].choices = choices
but this show:
category name
in option. How to do it?
I see two answers:
you may use unicode blank caracter (alt gr + 0160 on windows) instead of (it's the best way to triforce).
⠀▲⠀, ctrl+shift+u -> 2800 on gnome
▲⠀▲, copying caracter between thoses triangles.
simply use "mark_safe" function on your string if you want to use it as raw html without any escaping... (you may want to escape first part of the string before marking safe the whole one.)
Related
I am using Aspose library for Word merge.
In the previous version of the Aspose, if we add white spaces for a field then while merging , it doesn't considers it as empty but after upgrade to latest version, it is considering the whitespaces as blank and removing those fields if setting is ON.
For my case, I want to prevent whitespaces or empty fields for few fileds but remove it for rest of the fields.
I tried to find a setting which can be applied on field level to prevent or remove empty fields but have'nt got any.
Is there any way I can acheive this?
If paragraph contains only whitespaces it is considered as empty and is removed. So for example if you use code like the following:
string[] fieldNames = new string[] { "FirstName", "MidName", "LastName" };
string[] fieldValues = new string[] { "Alexey", " ", "Noskov" };
Document doc = new Document(#"C:\Temp\in.docx");
doc.MailMerge.CleanupOptions = MailMergeCleanupOptions.RemoveEmptyParagraphs;
doc.MailMerge.Execute(fieldNames, fieldValues);
doc.Save(#"C:\Temp\out.docx");
Where MidName merge field is placed in a separate paragraph, the paragraph will be removed as empty.
However, you can work this behavior around using IFieldMergingCallback. For example, you can put hidden text at the merge field to make the paragraph to be considered as not empty. For example see the following code:
string[] fieldNames = new string[] { "FirstName", "MidName", "LastName" };
string[] fieldValues = new string[] { "Alexey", " ", "Noskov" };
Document doc = new Document(#"C:\Temp\in.docx");
doc.MailMerge.FieldMergingCallback = new MergeWhitespaceCallback("MidName");
doc.MailMerge.CleanupOptions = MailMergeCleanupOptions.RemoveEmptyParagraphs;
doc.MailMerge.Execute(fieldNames, fieldValues);
doc.Save(#"C:\Temp\out.docx");
private class MergeWhitespaceCallback : IFieldMergingCallback
{
private readonly string[] mRetainParagraphsWithFields;
public MergeWhitespaceCallback(params string[] retainParagraphsWithFields)
{
mRetainParagraphsWithFields = retainParagraphsWithFields;
}
public void FieldMerging(FieldMergingArgs args)
{
if (!string.IsNullOrEmpty(args.FieldValue.ToString().Trim()))
return;
if (!mRetainParagraphsWithFields.Contains(args.FieldName))
return;
DocumentBuilder builder = new DocumentBuilder(args.Document);
builder.MoveTo(args.Field.Start);
builder.Font.Hidden = true;
builder.Write("<empty paragraph>");
}
public void ImageFieldMerging(ImageFieldMergingArgs args)
{
// Do nothing.
}
}
Later, you can remove hidden text if required.
Assuming you're actually executing a mailmerge (not just overwriting mergefields), you should be able to control most, if not all, of that via mailmerge field coding in the mailmerge main document.
On PCs, you can use the mergefield \b and/or \f switches to suppress a space before or after an empty mergefield. For example, suppose you have:
«Title» «FirstName» «SecondName» «LastName»
but «SecondName» is sometimes empty and you don’t want that to leave two spaces in the output. To deal with that:
select the «SecondName» field and press Shift-F9 so that you get
{MERGEFIELD SecondName};
edit the field code so that you end up with-
{MERGEFIELD SecondName \b " "} or
{MERGEFIELD SecondName \f " "}
depending on whether the space to be suppressed is following or before the mergefield;
delete, as appropriate, the corresponding space following or before
the mergefield;
position the cursor anywhere in this field and press F9 to update it.
Note 1: the \b and \f switches don't work on Macs or in conjunction with other switches. In such cases you need to use and IF test instead, coded along the lines of-
{IF{MERGEFIELD SecondName}<> "" " {MERGEFIELD SecondName}"} or
{IF{MERGEFIELD SecondName}<> "" "{MERGEFIELD SecondName} "}
Even so, you can use the \b and \f switches to express other mergefields that do have switches of their own. For example, suppose you have four fields ‘Product’, ‘Supplier’, ‘Quantity’ and ‘UnitPrice’, and you don’t want to output the ‘Product’, ‘Quantity’ or ‘UnitPrice’ fields if the ‘Supplier’ field is empty. In that case, you might use a field coded along the lines of:
{MERGEFIELD "Supplier" \b "{MERGEFIELD Product}→" \f "→{MERGEFIELD Quantity \# 0}→{MERGEFIELD UnitPrice \# "$0.00"}¶
"}
Note 2: The field brace pairs (i.e. '{ }') for the above example are all created in the document itself, via Ctrl-F9 (Cmd-F9 on a Mac or, if you’re using a laptop, you might need to use Ctrl-Fn-F9); you can't simply type them or copy & paste them from this message. Nor is it practical to add them via any of the standard Word dialogues. Likewise, the chevrons (i.e. '« »') are part of the actual mergefields - which you can insert from the 'Insert Merge Field' dropdown (i.e. you can't type or copy & paste them from this message, either). The spaces represented in the field constructions are all required. Instead of the →, ↵ and ¶ symbols, you should use real tabs and line/paragraph breaks, respectively.
For more Mailmerge Tips & Tricks, see: https://www.msofficeforums.com/mail-merge/21803-mailmerge-tips-tricks.html
I am trying to use
class reader
def __init__(self, name, booksread)
self.name = name
self.booksread = booksread
while True
option = input("Choose an option: ")
if option = 1:
#What to put here?
I want to create an unlimited number of instances of the reader class, But I could only figure out how to do it a limited number of times by using variables for the class. I also need to call the info later (without losing it). Is it possible to do this with a class? Or would I be better off with a list, or dictionary?
First: if option == 1: is always false in python 3, input only reads strings there.
Second: python lists can be expanded until you run out of RAM.
So the solution would be to create a list in the surrounding code and call append on that every time you have a new item:
mylist = []
while True:
mylist.append(1)
It's perfectly possibly to populate a data structure (such as a list or dict) with instances of a class, given your code example you could put the instances into a list:
class reader
def __init__(self, name, booksread)
self.name = name
self.booksread = booksread
list = []
while True:
option = input("Choose an option: ")
if option == 1:
list.append(reader(name,booksread))
Note: I don't know how you are obtaining the values for 'name' or 'booksread', so their values in the list.append() line are just placeholders
To access the instances in that list, you can then iterate over it, or access elements by their indexes, e.g.
# access each element of the list and print the name
for reader in list:
print(reader.name)
#print the name of the first element of the list
print(list[0].name)
I've read the other threads on this site but haven't quite grasped how to accomplish what I want to do. I'd like to find a method like .splitlines() to assign the first two lines of text in a multiline string into two separate variables. Then group the rest of the text in the string together in another variable.
The purpose is to have consistent data-sets to write to a .csv using the three variables as data for separate columns.
Title of a string
Description of the string
There are multiple lines under the second line in the string!
There are multiple lines under the second line in the string!
There are multiple lines under the second line in the string!
Any guidance on the pythonic way to do this would be appreciated.
Using islice
In addition to normal list slicing you can use islice() which is more performant when generating slices of larger lists.
Code would look like this:
from itertools import islice
with open('input.txt') as f:
data = f.readlines()
first_line_list = list(islice(data, 0, 1))
second_line_list = list(islice(data, 1, 2))
other_lines_list = list(islice(data, 2, None))
first_line_string = "".join(first_line_list)
second_line_string = "".join(second_line_list)
other_lines_string = "".join(other_lines_list)
However, you should keep in mind that the data source you read from is long enough. If it is not, it will raise a StopIteration error when using islice() or an IndexError when using normal list slicing.
Using regex
The OP asked for a list-less approach additionally in the comments below.
Since reading data from a file leads to a string and via string-handling to lists later on or directly to a list of read lines I suggested using a regex instead.
I cannot tell anything about performance comparison between list/string handling and regex operations. However, this should do the job:
import re
regex = '(?P<first>.+)(\n)(?P<second>.+)([\n]{2})(?P<rest>.+[\n])'
preg = re.compile(regex)
with open('input.txt') as f:
data = f.read()
match = re.search(regex, data, re.MULTILINE | re.DOTALL)
first_line = match.group('first')
second_line = match.group('second')
rest_lines = match.group('rest')
If I understand correctly, you want to split a large string into lines
lines = input_string.splitlines()
After that, you want to assign the first and second line to variables and the rest to another variable
title = lines[0]
description = lines[1]
rest = lines[2:]
If you want 'rest' to be a string, you can achieve that by joining it with a newline character.
rest = '\n'.join(lines[2:])
A different, very fast option is:
lines = input_string.split('\n', maxsplit=2) # This only separates the first to lines
title = lines[0]
description = lines[1]
rest = lines[2]
To make things easier but also more complicated, I tried to implement a concept of "combined / concise tags" that expand further on into multiple basic tag forms.
In this case the tags consist of (one or more) "sub-tag(s)", delimited by semicolons:
food:fruit:apple:sour/sweet
drink:coffee/tea:hot/cold
wall/bike:painted:red/blue
Slashes indicate "sub-tag" interchangeability.
Therefore the interpreter translates them to this:
food:fruit:apple:sour
food:fruit:apple:sweet
drink:coffee:hot
drink:coffee:cold
drink:tea:hot
drink:tea:cold
wall:painted:red
wall:painted:blue
bike:painted:red
bike:painted:blue
The code used (not perfect, but works):
import itertools
def slash_split_tag(tag):
if not '/' in tag:
return tag
subtags = tag.split(':')
pattern, v_pattern = (), ()
for subtag in subtags:
if '/' in subtag:
pattern += (None,)
v_pattern += (tuple(subtag.split('/')),)
else:
pattern += (subtag,)
def merge_pattern_and_product(pattern, product):
ret = list(pattern)
for e in product:
ret[ret.index(None)] = e
return ret
CartesianProduct = tuple(itertools.product(*v_pattern)) # http://stackoverflow.com/a/170248
return [ ':'.join(merge_pattern_and_product(pattern, product)) for product in CartesianProduct ]
#===============================================================================
# T E S T
#===============================================================================
for tag in slash_split_tag('drink:coffee/tea:hot/cold'):
print tag
print
for tag in slash_split_tag('A1/A2:B1/B2/B3:C1/C2:D1/D2/D3/D4/EE'):
print tag
Question: How can I possibly revert this process? I need this for readability reasons.
Here's a simple, first-pass attempt at such a function:
def compress_list(alist):
"""Compress a list of colon-separated strings into a more compact
representation.
"""
components = [ss.split(':') for ss in alist]
# Check that every string in the supplied list has the same number of tags
tag_counts = [len(cc) for cc in components]
if len(set(tag_counts)) != 1:
raise ValueError("Not all of the strings have the same number of tags")
# For each component, gather a list of all the applicable tags. The set
# at index k of tag_possibilities is all the possibilities for the
# kth tag
tag_possibilities = list()
for tag_idx in range(tag_counts[0]):
tag_possibilities.append(set(cc[tag_idx] for cc in components))
# Now take the list of tags, and turn them into slash-separated strings
tag_possibilities_strs = ['/'.join(tt) for tt in tag_possibilities]
# Finally, stitch this together with colons
return ':'.join(tag_possibilities_strs)
Hopefully the comments are sufficient in explaining how it works. A few caveats, however:
It doesn't do anything sensible such as escaping backslashes if it finds them in the list of tags.
This doesn't recognise if there's a more subtle division going on, or if it gets an incomplete list of tags. Consider this example:
fish:cheese:red
chips:cheese:red
fish:chalk:red
It won't realise that only cheese has both fish and chips, and will instead collapse this to fish/chips:cheese/chalk:red.
The order of the tags in the finished string is random (or at least, I don't think it has anything to do with the order of the strings in the given list). You could sort tt before you join it with slashes if that's important.
Testing with the three lists given in the question seems to work, although as I said, the order may be different to the initial strings:
food:fruit:apple:sweet/sour
drink:tea/coffee:hot/cold
wall/bike:painted:blue/red
Having the following HTML code:
<span class="warning" id ="warning">WARNING:</span>
For an object accessible by XPAth:
.//*[#id='unlink']/table/tbody/tr[1]/td/span
How can one count its attributes (class, id) by means of Selenium WebDriver + Python 2.7, without actually knowing their names?
I'm expecting something like count = 2.
Got it! This should work for div, span, img, p and many other basic elements.
element = driver.find_element_by_xpath(xpath) #Locate the element.
outerHTML = element.get_attribute("outerHTML") #Get its HTML
innerHTML = element.get_attribute("innerHTML") #See where its inner content starts
if len(innerHTML) > 0: # Let's make this work for input as well
innerHTML = innerHTML.strip() # Strip whitespace around inner content
toTrim = outerHTML.index(innerHTML) # Get the index of the first part, before the inner content
# In case of moste elements, this is what we care about
rightString = outerHTML[:toTrim]
else:
# We seem to have something like <input class="bla" name="blabla"> which is good
rightString = outerHTML
# Ie: <span class="something" id="somethingelse">
strippedString = rightString.strip() # Remove whitespace, if any
rightTrimmedString = strippedString.rstrip('<>') #
leftTrimmedString = rightTrimmedString.lstrip('</>') # Remove the <, >, /, chars.
rawAttributeArray = leftTrimmedString.split(' ') # Create an array of:
# [span, id = "something", class="somethingelse"]
curatedAttributeArray = [] # This is where we put the good values
iterations = len(rawAttributeArray)
for x in range(iterations):
if "=" in rawAttributeArray[x]: #We want the attribute="..." pairs
curatedAttributeArray.append(rawAttributeArray[x]) # and add them to a list
numberOfAttributes = len(curatedAttributeArray) #Let's see what we got
print numberOfAttributes # There we go
I hope this helps.
Thanks,
R.
P.S. This could be further enhanced, like stripping whitespace together with <, > or /.
It's not going to be easy.
Every element has a series of implicit attributes as well as the ones explicitly defined (for example selected, disabled, etc). As a result the only way I can think to do it would be to get a reference to the parent and then use a JavaScript executor to get the innerHTML:
document.getElementById('{ID of element}').innerHTML
You would then have to parse what is returned by innerHTML to extract out individual elements and then once you have isolated the element that you are interested in you would again have to parse that element to extract out a list of attributes.