diff --git a/doc/guide/publisher/publication-file.xml b/doc/guide/publisher/publication-file.xml index 78eeff083c..25a1170b5e 100644 --- a/doc/guide/publisher/publication-file.xml +++ b/doc/guide/publisher/publication-file.xml @@ -1023,6 +1023,20 @@

+ + Interactive Processing +

The attribute + + /publication/webwork/@interactive-processing + + can have value webwork2 (the default). Once the standalone PG renderer is + better at supporting live rendering, it will also be possible to set this to + renderer. When exercises are live, embedded in HTML, this + is the method that will be used. Either communicating with a webwork2 server + or a PG renderer. +

+
+ PG Location

The attribute @@ -1035,6 +1049,20 @@

+ + PG Renderer +

+ The URL to a PG renderer instance is in the attribute + + /publication/webwork/@renderer + + It should include the protocol (e.g.http or https) and not + include a trailing slash. The renderer should use PG 2.19 or later. The default + value is https://webwork-dev.aimath.org. At this time, this is the only + instance of the PG renderer that is configured to work for . +

+
+ Server

diff --git a/doc/guide/publisher/webwork.xml b/doc/guide/publisher/webwork.xml index 8689c8ffac..c4f9dcc996 100644 --- a/doc/guide/publisher/webwork.xml +++ b/doc/guide/publisher/webwork.xml @@ -17,10 +17,10 @@

- You can embed exercises in your project. This requires using a - webwork2 server that is version 2.16 or later. The server could be the AIM - server that has been set up for this purpose, so to get started, there is no need to establish - your own webwork2 server. + You can embed exercises in your project. This requires using either a + webwork2 server that is version 2.16 or later, or a PG renderer that uses PG 2.19 or + later. Either of these could be AIM servers that have been set up for this purpose, so to get + started, there is no need to establish your own webwork2 server or PG renderer.

Part of the process can optionally be sped up by using a local copy of the pg @@ -177,6 +177,27 @@

+
+ Using a PG rendering service +

+ problems can be processed using a standalone PG renderer. At this time, this + feature is under development. There is one functional renderer on an AIM server. We hope to + make the renderer something that is easy for anyone to install at other locations. The + renderer is more lightweight than a webwork2 server and runs significantly faster + (although not as fast as using local pg). +

+

+ To use this processing method, in a publisher file, you can set the webwork element + to have static-processing with value renderer. This will use the AIM + instance of the renderer. When the renderer becomes something you can install on other + servers, you will have another publisher option to specify where it is. +

+

+ At this time, you will still need to use a webwork2 server for problems in your HTML + output to render as live interactive exercises. +

+
+
Configuring a <c>webwork2</c> Server for <pretext/>

@@ -189,7 +210,7 @@ needs to be 2.16 or later for use with .

- The only thing you need to do at the serverlevel is set the web server to use certain headers + The only thing you need to do at the server level is set the web server to use certain headers on content that is fetched. These headers tell a web browser that you are authorizing it to display content from this web server as embedded content inside pages from another web server (in particular, where you are hosting you book). @@ -295,7 +316,7 @@ Allowed to view course home page which should also be set to login_proctor.

- In the Accounts Manager(Classlist Editor in older versions of ), add a user named + In the Accounts Manager (Classlist Editor in older versions of ), add a user named anonymous (again, you could use some other name), and set that user's permission level to login_proctor, the permission level one higher than student. Set that user's password to anonymous (again, you could use some other password). Note that because @@ -362,30 +383,34 @@

- PG Macros from the <pretext/> Source + PG Macros from the <pretext/> source

The project's exercises may rely on PG macros that are written into the project's source. For example, the exercises might have TikZ images that rely on docinfo/latex-image-preamble.

- For this, a PG macro library file must be built and placed in the host course's - templates/macros/ folder before attempting to process the - exercises. To build this macro library, run: + For this, a PG macro library file must be built and placed wherever it is needed. To build + this macro library, run: - pretext -c pg-macros aota.ptx - - aota.ptx in the example is the root file for your project. You could also - specify a location to place the resulting macro library file: - - pretext -c pg-macros -d some/file/path aota.ptx + pretext/pretext/pretext -c pg-macros -p publication.xml mainfile.ptx +

+ This will place the PG macros file in generated/webwork/pg/[TITLE]/macros/ where + [TITLE] is a file-safe version of the title of your project. If you are using a host + course on a webwork2 server, plase this macros file in that course's macros folder.

- Once you have the macro library file, upload it to the host course's - templates/macros folder. If your project relies on the AIM server and you - need to supply a macro library file to a host course on that server, post to - pretex-support@googlegroups.com and we can help with that. + If the project's source changes in such a way that these PG macros would change, this file + should be regenerated.

@@ -535,7 +560,8 @@ that you wrote, set defintion files corresponding to the sections (or other chunks) of your project, and header files for those sets. All of this was placed into your project's generated/webwork/pg folder when you executed pretext -c webwork, so you could - find it there and package it all up to send to your server.

+ find it there and package it all up to send to your server. +

Alternativley, you may run the following:

@@ -568,33 +594,9 @@
  • - Certain aspects of specifying borders of a tabular are not - realizable in a PGML table. Specifically, -

      -
    • -

      - Specifying column-specific top border attributes are not implemented. -

      -
    • -
    • -

      - Cell-specific bottom border attributes are not implemented. -

      -
    • -
    • -

      - medium and major table rule-thickness attributes will be handled as - if they were minor. -

      -
    • -
    -

    -
  • -
  • -

    - When constructing a list (ul or ol) specifying some number of - columns (using the cols attribute) will be ignored. PGML markup has no way - to declare multicolumn lists. + When constructing a list (ul or ol) + specifying some number of columns (using the cols attribute) + will be ignored. PGML markup has no way to declare multicolumn lists.

  • diff --git a/examples/webwork/Makefile b/examples/webwork/Makefile index 2d159c85c7..287c0feb3e 100644 --- a/examples/webwork/Makefile +++ b/examples/webwork/Makefile @@ -114,15 +114,16 @@ PGOUT = $(SCRATCH)/pg # folder. There are no macros for the minimal example, so omitted. sample-chapter-macros: - install -d $(PGOUT)/macros - cd $(PGOUT)/macros; \ - $(PTX)/pretext/pretext -v -c pg-macros -p $(SMPCPUB) $(SMPC) + $(PTX)/pretext/pretext -v -c pg-macros -p $(SMPCPUB) -d $(PGOUT)/macros $(SMPC) ######################################################################### # Extract webwork problems into a single XML file. # Location is within generated folder (named in the publisher file), # within "webwork" subfolder +# This also produces PG files for each problem, PG macros, set defintion +# files for problem sets, and set header files all within the "webwork/pg" +# folder sample-chapter-representations: $(PTX)/pretext/pretext -v -c webwork -p $(SMPCPUB) $(SMPC) diff --git a/examples/webwork/minimal/external/images/webwork-logo.png b/examples/webwork/minimal/external/images/webwork-logo.png deleted file mode 100644 index 8b1ff68554..0000000000 Binary files a/examples/webwork/minimal/external/images/webwork-logo.png and /dev/null differ diff --git a/examples/webwork/minimal/publication.xml b/examples/webwork/minimal/publication.xml index 290cda6078..2f74fc6b4b 100644 --- a/examples/webwork/minimal/publication.xml +++ b/examples/webwork/minimal/publication.xml @@ -28,6 +28,14 @@ along with PreTeXt. If not, see . + ` + '' + + '' + '
    ' + form.outerHTML + '
    ' + ''; diff --git a/pretext/lib/pretext.py b/pretext/lib/pretext.py index fe995e764f..1b7c63c207 100644 --- a/pretext/lib/pretext.py +++ b/pretext/lib/pretext.py @@ -1165,6 +1165,7 @@ def webwork_to_xml( extracted_pg_xml = ET.parse(extracted_pg_filename).getroot() localization = extracted_pg_xml.get("localization") webwork2_server = extracted_pg_xml.find("server-params-pub").get("webwork2-server") + renderer_server = extracted_pg_xml.find("server-params-pub").get("renderer") numbered_title_filesafe = extracted_pg_xml.get("numbered-title-filesafe") ww_project_dir = os.path.join(ww_reps_dir, "pg", numbered_title_filesafe) if not (os.path.isdir(ww_project_dir)): @@ -1174,7 +1175,7 @@ def webwork_to_xml( os.mkdir(ww_macros_dir) # construct the generated pg files, etc, which may need to be read later for rendering problems - webwork_sets(xml_source, pub_file, stringparams, ww_pg_dir, False) + webwork_sets(xml_source, pub_file, stringparams, ww_pg_dir, False, False) pg_macros(xml_source, pub_file, stringparams, ww_macros_dir) no_publication_file = False @@ -1185,6 +1186,7 @@ def webwork_to_xml( "user": extracted_pg_xml.find("server-params-pub").get("user-id"), "passwd": extracted_pg_xml.find("server-params-pub").get("password"), "disableCookies": '1', + "renderer": renderer_server } static_processing = extracted_pg_xml.find("processing").attrib["static"] pg_location = extracted_pg_xml.find("processing").attrib["pg-location"] @@ -1196,8 +1198,10 @@ def webwork_to_xml( "user": "anonymous", "passwd": "anonymous", "disableCookies": '1', + "renderer": "https://webwork-dev.aimath.org" } static_processing = 'webwork2' + interactive_processing = 'webwork2' pg_location = '/opt/webwork/pg' # ideally, pub_file is in use, in which case server_params_pub is nonempty. @@ -1235,6 +1239,8 @@ def webwork_to_xml( courseID = server_params_pub["courseID"] user = server_params_pub["user"] passwd = server_params_pub["passwd"] + if static_processing == "renderer": + renderer = sanitize_url(server_params_pub["renderer"]) webwork2_domain_webwork2 = webwork2_domain + "/webwork2/" webwork2_render_rpc = webwork2_domain_webwork2 + "render_rpc" @@ -1250,6 +1256,12 @@ def webwork_to_xml( or (extracted_pg_xml.xpath("//problem[@origin='webwork2']")) ) + # Establish if there is any need to use renderer + need_for_renderer = ( + (static_processing == 'renderer') + and (extracted_pg_xml.xpath("//problem[@origin!='webwork2']")) + ) + # Establish if there is any need to use a socket need_for_socket = ( (static_processing == 'local') @@ -1264,6 +1276,8 @@ def webwork_to_xml( raise ImportError(__module_warning.format("requests")) # Establish WW server version, for live rendering if nothing else + # Note: if the renderer is doing live rendering there may be no need for a WW server and + # this entire block can be conditioned on need_for_webwork2 # First try to identify the WW version according to what a response hash says it is. # This should work for 2.17 and beyond. try: @@ -1317,7 +1331,7 @@ def webwork_to_xml( + " Is there a WeBWorK landing page at {}?\n" + " And does it display the WeBWorK version?\n" ) - raise ValueError(msg.format(webwork2_version, webwork2_domain)) + raise ValueError(msg.format(webwork2_domain_webwork2)) webwork2_path = webwork2_render_rpc if (webwork2_major_version == 2 and webwork2_minor_version >= 19) else webwork2_html2xml @@ -1346,13 +1360,16 @@ def webwork_to_xml( + " Server: {}\n" + " You may want to use the AIM WeBWorK server at webwork-ptx.aimath.org.\n" ) - raise ValueError(msg.format(ww_version, ww_domain)) + raise ValueError(msg.format(webwork2_version, webwork2_domain)) # using a "Session()" will pool connection information # since we always hit the same server, this should increase performance if need_for_webwork2: webwork2_session = requests.Session() + if need_for_renderer: + renderer_session = requests.Session() + clientsocket = None if need_for_socket: @@ -1431,7 +1448,7 @@ def webwork_to_xml( # but kill this for the code that is used repeatedly by embedded problems in HTML # So here we branch a copy for embedding where we kill `$refreshCachedImages=1;` # But we can't literally just remove that, since an author may have used something - # like `$refreshCachedImages = 'true' ;` so instead, we change `$refreshCachedImages` + # like `$refreshCachedImages = 'true' ;` so instead, we change `refreshCachedImages` # to something inert if origin[problem] == "generated": embed_problem = re.sub(r'(refreshCachedImages)(?![\w\d])', r'\1Inert', pgdense[problem]) @@ -1463,6 +1480,32 @@ def webwork_to_xml( response = buffer.decode().replace('ENDOFSOCKETDATA', '') + elif static_processing == 'renderer' and origin[problem] != 'webwork2': + if origin[problem] == "external": + with open(os.path.join(external_dir, path[problem])) as f: rawProblemSource = f.read() + server_params_source = {"rawProblemSource":rawProblemSource} + else: + server_params_source = {"rawProblemSource":pgdense[problem]} + + server_params = { + "showSolutions": "1", + "showHints": "1", + "displayMode": "PTX", + "courseID": courseID, + "user": user, + "passwd": passwd, + "outputformat": "ptx", + "problemSeed": seed[problem], + "problemUUID": problem, + } + server_params.update(server_params_source) + + msg = "sending {} to renderer to save in {}: origin is '{}'" + log.info(msg.format(problem, ww_reps_file, origin[problem])) + + response = renderer_session.post(renderer + '/renderer/render-ptx', data=server_params) + response = response.text + else: # Construct URL to get static version from server # First establish how the acctual problem code @@ -1685,7 +1728,10 @@ def webwork_to_xml( if static_processing == 'local' and origin[problem] != 'webwork2': ww_image_scheme = '' else: - ww_image_url = urllib.parse.urljoin(webwork2_domain, ww_image_full_path) + if static_processing == 'renderer' and origin[problem] != 'webwork2': + ww_image_url = urllib.parse.urljoin(renderer, ww_image_full_path) + else: + ww_image_url = urllib.parse.urljoin(webwork2_domain, ww_image_full_path) # strip away the scheme and location, if present (e.g 'https://webwork-ptx.aimath.org/') ww_image_url_parsed = urllib.parse.urlparse(ww_image_url) ww_image_scheme = ww_image_url_parsed.scheme @@ -1753,7 +1799,10 @@ def webwork_to_xml( # download actual image files # http://stackoverflow.com/questions/13137817/how-to-download-image-using-requests try: - image_response = webwork2_session.get(image_url) + if static_processing == 'renderer' and origin[problem] != 'webwork2': + image_response = renderer_session.get(image_url) + else: + image_response = webwork2_session.get(image_url) except requests.exceptions.RequestException as e: root_cause = str(e) msg = "PTX:ERROR: there was a problem downloading an image file,\n URL: {}\n" @@ -1929,6 +1978,7 @@ def static_webwork_level(write, read): rendering_data.set(source_key, source_value) rendering_data.set("origin", origin[problem]) rendering_data.set("domain", webwork2_domain) + rendering_data.set("renderer", renderer_server) rendering_data.set("course-id", courseID) rendering_data.set("user-id", user) rendering_data.set("passwd", passwd) @@ -1976,6 +2026,10 @@ def static_webwork_level(write, read): webwork2_session.close() except: pass + try: + renderer_session.close() + except: + pass # close the socket if clientsocket: @@ -1988,7 +2042,7 @@ def static_webwork_level(write, read): ################################ -def webwork_sets(xml_source, pub_file, stringparams, dest_dir, tgz): +def webwork_sets(xml_source, pub_file, stringparams, dest_dir, tgz, need_macros=True): # to ensure provided stringparams aren't mutated unintentionally stringparams = stringparams.copy() @@ -2005,7 +2059,8 @@ def webwork_sets(xml_source, pub_file, stringparams, dest_dir, tgz): folder = os.path.join(tmp_dir, folder_name) macros_folder = os.path.join(folder, 'macros') os.mkdir(macros_folder) - pg_macros(xml_source, pub_file, stringparams, macros_folder) + if need_macros: + pg_macros(xml_source, pub_file, stringparams, macros_folder) if tgz: archive_file = os.path.join(tmp_dir, folder_name + ".tgz") targz(archive_file, folder) @@ -2033,7 +2088,12 @@ def pg_macros(xml_source, pub_file, stringparams, dest_dir): stringparams["publisher"] = pub_file ptx_xsl_dir = get_ptx_xsl_path() extraction_xslt = os.path.join(ptx_xsl_dir, "support", "pretext-pg-macros.xsl") - xsltproc(extraction_xslt, xml_source, None, output_dir=dest_dir, stringparams=stringparams) + tmp_dir = get_temporary_directory() + xsltproc(extraction_xslt, xml_source, None, output_dir=tmp_dir, stringparams=stringparams) + copy_build_directory(tmp_dir, dest_dir) + #folder_name = os.listdir(tmp_dir)[0] + #folder = os.path.join(tmp_dir, folder_name) + #copy_build_directory(folder, os.path.join(dest_dir,folder_name)) ############################################################ # diff --git a/pretext/pretext b/pretext/pretext index a13acef09d..bb0c27c8fa 100755 --- a/pretext/pretext +++ b/pretext/pretext @@ -326,10 +326,10 @@ def get_cli_arguments(): ("latex-image", "LaTeX pictures (method: [xelatex], pdflatex)"), ( "webwork", - "WeBWorK problems in authored, PG, url, and static representations", + "WeBWorK problems in PG files and various representations", ), ("references", "References and citations via Citation Stylesheet Language"), - ("pg-macros", "Server-side macros for WeBWorK problem generation"), + ("pg-macros", "PG macros for WeBWorK problem generation"), ("dynamic", "Expression subsitutions for dynamically generated exercises"), ("youtube", "Thumbnails for YouTube videos (JPEG only)"), ("play-button", "generate generic static video image"), @@ -387,7 +387,7 @@ def get_cli_arguments(): ), ("assembly-version", "PreTeXt source, after pre-processor resolves versions and customizations (for developers)", ), ("sagenb", "Sage worksheet conversion (removed)"), - ("webwork-sets", "Folder tree of PG files, set definitions, and set headers"), + ("webwork-sets", "Folder tree of PG files, PG macros, set definitions, and set headers"), ("all", "All available output formats"), ] format_help = "Output formats are:\n" + "\n".join( diff --git a/xsl/extract-pg.xsl b/xsl/extract-pg.xsl index e7b7a52607..3a0c50243e 100644 --- a/xsl/extract-pg.xsl +++ b/xsl/extract-pg.xsl @@ -146,6 +146,9 @@ + + + @@ -770,36 +773,7 @@ Header - TEXT(beginproblem()); - - - - - - - - <div style="display:none;">\( - - \)</div> - - - - - - - - - - TEXT(MODES(PTX=>'',HTML=> - - q - - - - - )); - - + TEXT(beginproblem()); @@ -1581,6 +1555,9 @@ + + + [@image(insertGraph( ), width=> @@ -1679,40 +1656,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1729,7 +1672,7 @@ - + @@ -1739,35 +1682,157 @@ - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - + - - - - + >> - + - + << + + + + + + + + + + + + + + + + + + + + [. + + + + .] + + + * + + + { + + } + +>>>>>>> e9c566e3 (WeBWorK: xsl and pretext for 2.19) + + + + + + + + + + align => ' + + p{ + + > + + } + + ', + + + align => '*{ + + }{p{ + + }}', + + + + valign => ' + + ', + + + + [# + + #]* + + { + + } + + + + + + + + + + + + + + + align => 'p{ + + }*{ + + }', + + + valign => ' + + ', + + + + [# + + + + #]* + + { + + } + + @@ -1795,10 +1860,6 @@ - - - - @@ -1811,9 +1872,6 @@ [` - - - @@ -1823,19 +1881,24 @@ - + + + + [``` - - - - ```] - + ```] + + + + @@ -1908,21 +1971,25 @@ - + + + + [``` - - - ```] - - + + + + @@ -2403,7 +2470,10 @@ - ``` + ``` + + + @@ -2549,7 +2619,9 @@ - + + + @@ -2566,7 +2638,9 @@ - + + + [@DataTable( @@ -2622,6 +2696,7 @@ + );@]* @@ -3121,7 +3196,7 @@ - + diff --git a/xsl/pretext-html.xsl b/xsl/pretext-html.xsl index 864fa38fa7..7181a48835 100644 --- a/xsl/pretext-html.xsl +++ b/xsl/pretext-html.xsl @@ -10725,6 +10725,12 @@ along with MathBook XML. If not, see . + + + + + + @@ -10752,7 +10758,6 @@ along with MathBook XML. If not, see . - @@ -13709,17 +13714,23 @@ TODO: + + + + + + + \newcommand{\sfrac}[2]{{#1}/{#2}} + + diff --git a/xsl/publisher-variables.xsl b/xsl/publisher-variables.xsl index 47884d8cd7..68b44e25a0 100644 --- a/xsl/publisher-variables.xsl +++ b/xsl/publisher-variables.xsl @@ -1264,12 +1264,23 @@ along with PreTeXt. If not, see . + + + + + - + + + + + + + @@ -1299,7 +1310,6 @@ along with PreTeXt. If not, see . - @@ -3263,8 +3273,10 @@ along with PreTeXt. If not, see . - + + + diff --git a/xsl/support/pretext-pg-macros.xsl b/xsl/support/pretext-pg-macros.xsl index 7ab3fb921e..4b0f96304b 100644 --- a/xsl/support/pretext-pg-macros.xsl +++ b/xsl/support/pretext-pg-macros.xsl @@ -71,6 +71,7 @@ + @@ -80,6 +81,15 @@ + + + + + + + + + # Return a string containing the latex-image-preamble contents. @@ -104,7 +114,7 @@ ############################################################################# - +