Converting a string automatically into a link to a pdf document - string

I've done some looking around in here and on the internet and it doesnt seem super obvious, but my question is can python using tkinter be used to automatically convert a text string into a link that loads a pdf from a certain direction
e.g. data '12345 Issue A' pops up in a text widget and is automatically converted to a link that when clicked opens up a pdf document.
Can this or can it not be done ?
In this case I'm wanting to be able to click 1931-125, 699-126 and 1851-127 and have each open up a pdf file of the same name. This is being used in a manufacturing environment and allows an assembler to click the fields and have all the documents they need to build a certain item

First off to apply formatting to parts of a Text widget you will need to understand about tags, in most cases you can probably just use the phrase of the link (ABC123) just remember that:
The name of a tag can be any string that does not contain white space or periods.
once you have a tag for the link there are two parts:
Formatting the tag to look and react like a link.
Applying the tag to the phrases in text.
The first one is really simple if you just want it to be blue and underlined and respond to being clicked:
def format_link(text_widget,tag,command):
text_widget.tag_config(tag,foreground="blue",underline=1)
text_widget.tag_bind(tag,"<Button-1>",command)#remember that the command will need to take an event argument
Although this could get more complicated if you want the cursor to change when hovering over or colour to change after clicking etc.
The second part is to apply this tag to the text automatically which I'm assuming means parse the text after it is inserted into the widget. This is also very simple by putting this answer in a loop so that it checks for every occurrence of the phrase:
def apply_tag(text_widget,phrase,tag,regexp=False):
countVar = tk.IntVar(text_widge)
idx = "1.0"
while idx:
idx = text_widget.search(phrase,idx, stopindex = "end",
count = countVar, regexp = regexp)
if idx:
end_idx = "%s + %sc" %(idx, countVar.get())
text_widget.tag_add(tag, idx, end_idx)
idx = end_idx
Then all that is left is defining the way to open the file in another program and then calling the two above functions, using os.system("open"...) to open files it could be as simple as:
def make_link(text,phrase,file_to_open):
def callback(event=None):
os.system("open %r"%file_to_open)#there are better ways of handling this
apply_tag(text,phrase,phrase)#uses phrase as tag
format_link(text,phrase,callback)
Although you might want to look at answers here or it's duplicate for alternatives for opening files.
after inserting the text into the widget, assuming you have some sort of list of phrases to turn into links, you can just loop over the phrases and call make_link for each one:
phrases = {"1931-125", "699-126", "1851-127"}
for s in phrases:
make_link(TEXT_W, s, s+".pdf") #make a link to same name with .pdf added to end.

Related

How to check if a selenium webelement has no sub tag in it which holds 'text'

I have a web element that sometimes delay loading or do not load properly. But when it loads, it will have a number as text element. I need this text to check and do some process later. I am able to extract this text and convert as number when this webelement is loaded properly. When it loads, there will be a tag element inside and it will consist a text as well. (Just for understanding what I am trying to explain, showing you an image of it. I have copy pasted code below) My aim is to extract this text '201515' below.
There are series of elements and few are properly loaded and where as few are not. This is explained as:
But when the DOM does not load, the program just throws an error and my program aborts. Because it is not loaded properly, I will not have any anchor tag element and hence no text element item. Shown as below:
At this time if I am checking as my webelement.text, it neither gives none or null value. Is there any possiblity how I can make it load properly or precisely check if there is no element text present, make it load and redo the operation. Or is my understanding wrong and it doesnot load ever at all?
My python code:
for element_index in range(count_of_divs):
index = str(element_index + 1) # in web elements, it is one based index
xpath = '//*[#id="wrapped_grid"]/div[5]/div/div[' + index + ']/div[2]'
test_id = WebDriverWait(self.login.driver, self.login.DELAY).until(
EC.presence_of_element_located((By.XPATH, xpath)))
# Get the Test ID number
time.sleep(0.1)
if test_id.text != "":
test_id_num = int(test_id.text)
currentpage_test_ID_list.append(test_id_num
)
This shows I have some discrepancy and text is blank. But how can I make this element load properly and get the text.
Just for clear picture understanding, I am also adding screenshots of DOM. I copy pasted code above and it is not screenshot. Picture is only for understanding how it looks.
I appreciate all your feedback/support in this

Dash App Table links are not clickable - Python Web app issue

Dash App Table Not allowing links to be clickable. They appear to be clickable links when I hover my mouse over the title but do not do anything when I click on them.
The following is a function I am using to build the the table:
def build_rows(images,titles,author,category,price,link):
"""
builds a table body. All parameters expect a list type
"""
rows = []
for x in range(len(titles)):
rows.append(html.Tr([html.Img(src=images[x], height="100px"),
html.Td(dcc.Link(titles[x], href=link[x])), # <--- This the problem
html.Td(author[x]),
html.Td(category[x]),
html.Td(price[x]),
html.Td(link[x])]))
table_body = [html.Tbody(rows)]
return table_body
Thank you for your help.
NOTE: I always upvote and select a correct answer when applicable
If you just want a regular anchor tag with an href, then you want to use html.A (ie import dash_html_components as html) rather than dcc.Link.
The dcc.Link component is for use with the dcc.Location component, and allows to to create single page applications, by hooking up a callback function to the value of the current URL, returning different layout fragments into a specific container element. If this is what you're trying to do, see the docs on how to use the Location component.

selenium.common.exceptions.ElementNotVisibleException tring to select a span element

I am trying to navigate a website that stores documents related to several projects. To get to a specific project I need to search a project name by inputting it in the search bar and selecting from the search result. I am able to find the search bar and search for the project that I am interested in but, trying to click on the searched project gives me "element is not visible" exception.
There is also a recently viewed projects section and I can select every project in this list except the first one. This does not help my use case though as the project, that I am searching for, might not always be in the recently viewed list. And I cannot select the first project in this list (But that is a different question maybe for some other time)
Here is the python code that I am using
change_proj = find_element.ret_element_handle(browser, 'xpath', '//td/em/button[text()="Change project"]')
change_proj.click()
print("after change_proj")
# Search bar in pop up window to change project
search_bar = browser.find_elements_by_name("searchString")
search_bar[1].send_keys(projectName)
project = browser.find_element_by_xpath("//span[contains(., '" + projectName + "')]")
project.click()
# This is the line that generates the exception
With the great help available on internet, I have tried a) waiting for element to be clickable, b) moving to the element "project" using ActionChains c) trying different version of the xpath that looks for a specific text but, none of these have worked.
I am attaching the html of the page as the image (Some entries are blanked out for confidentiality)

Is there a way find a button by two of its properties in Puppeteer?

I am trying to click a button by using puppeteer, and I am trying to find it by two of its properties, aria-describedby and title, because it doesn't have an ID.
The value of the aria-describedby property is a name I set, however, the last two characters are numbers that changes itselves automatically to random numbers.
I've searched through regexp questions, JS questions, puppeteer's codes, but nothing that actually worked.
The closest I've come with is this:
//v1
const arr = await page.$x('//button[starts-with("aria-describedby", "someName")]');
await arr[1].click();
//v2
page.click('button[aria-describedby="someName20"][title="Click button"]');
I've tried different codes, but almost always I get undefined or no node found for selector
You can try css starts-with selector (^=):
button[aria-describedby^="someName"][aria-label="Click button"]
I'm lacking html code to go off of so its tough to pinpoint an answer, but whenever i have dynamic selectors to click that need two parameters, i search by contains text:
let toClick = await page.$x("//button[contains(text(),'someName20')][contains(text(),'Click button')]");
await toClick[0].click();
Note: the text() method only works on text nodes (i.e. <a>someName20</a>
), but you can interchange the first or second expression in the bracket to query a value of a property instead of the elements text value.

Python Docx line spacing for specific paragraph

Having looked through the docs, I am trying to figure out how to apply line spacing to a single paragraph, but it appears that any line spacing can only be done on a global scale using styles. Is there a way to isolate specific paragraphs while leaving the rest of the document as normal?
like this:
import docx
from docx.enum.text import WD_LINE_SPACING
text = 'Lorem ipsum...'
doc = Document()
para = doc.add_paragraph('text')
para.line_spacing = WD_LINE_SPACING.ONE_POINT_FIVE
The above code does not work of course and I can only guess that it is because line_spacing is a style level formatting. The other point about trying to localise this without doing styles is the portability of the document once built, if you cut and paste anything from one doc to another that may have been emailed to another computer runs the risk of reverting to the "Normal" style of the other machine. This can be prevented by not using document level styles (it's a nasty work around, but that is a word issue not a docx one.)
Line spacing is explained in the documentation here:
https://python-docx.readthedocs.io/en/latest/user/text.html#line-spacing
The short answer is you need to access the ParagraphFormat object on each paragraph and use .line_spacing_rule for that:
paragraph_format = paragraph.paragraph_format
paragraph_format.line_spacing_rule = WD_LINE_SPACING.ONE_POINT_FIVE
Yes, the above answer is for a specific paragraph.
If you want to configure for all the paragraphs in the document, you can do this.
document = Document()
style = document.styles['Normal']
style.paragraph_format.line_spacing = 0.5

Resources